wezten
wezten

Reputation: 2276

asp.net prevent multiple processes

I have code in my ASP.NET site that must not be run by 2 threads or processes concurrently, so I put it in a lock. This works assuming there is only one process, and since 'Maximum Worker Processes' is set to 1 in IIS, I felt that this is reasonable. However I did an experiment that makes me wonder:

I created this action:

public void Test()
{
    for (int i = 0; i < 100; i++)
    {
        System.IO.File.AppendAllText(@"c:\tmp\d.txt", $"a: {i}\n");
        System.Threading.Thread.Sleep(1000);
    }
}

and called it from my browser. I then switch a: to b:, compiled it, and called it from another browser tab. Then I opened d.txt, and I saw something like this:

b: 31
a: 67
b: 32
a: 68
b: 33
a: 69

Clearly there are 2 processes running at the same time, and my lock will not be enough. What is the best method of ensuring that my piece of code is not run concurrently?

Upvotes: 1

Views: 1249

Answers (3)

David Beavon
David Beavon

Reputation: 1205

The issue you described could be caused by either threads or processes.

Assuming you just want to solve this problem on a single machine, and you want to prevent multiple worker processes (as title implies) then you might just lock a file for the life of the worker process.

Eg. in Application_Start you can get the temp directory (System.IO.Path.GetTempPath), and then prepare a file name using a common identifier like the site name from IApplicationHost. Then lock the file with an exclusive lock (or die). I recommend putting something in the windows application before killing your worker process.

If/when your worker process dies, the file should be unlocked. You can even get it to delete itself using CreateFile and with FILE_FLAG_DELETE_ON_CLOSE.

Of course if your application might be hosted on multiple servers then you probably won't want to use this type of approach since it won't be sufficient.

Upvotes: 0

Dan Field
Dan Field

Reputation: 21661

It sounds like you're really looking for a queue or queue-like singleton service. Using regular ASP.NET WebAPI doesn't make that easy to do OOB. You could fiddle around with making it work, but instead I'd consider one of the following:

  1. Use an actual queue (MSMQ, Azure Service Bus Queue, Rabbit MQ, etc.) that your endpoints connect to, with a listener on that queue that does the actual work. That may not really give you the synchronous communication you want, but it would be sure to keep things ordered and single.
  2. Create a WCF service and decorate it with InstanceContextMode = InstanceContextMode.Single and ConcurrencyMode = ConcurrencyMode.Single. The WCF Framework will take care of making that work as a singleton for you. You could host it in a Windows Service instead of IIS, which would further make sure that multiple processes didn't and you'd have full control over the threading model.

Upvotes: 2

Aristos
Aristos

Reputation: 66641

For the case that you have here one way is to use mutex

    // The key can be part of the file name - 
    //   be careful not all characters are valid
    var mut = new Mutex(true, key);

    try
    {   
        // Wait until it is safe to enter.
        mut.WaitOne();

        // now call your file manipulation function
        Test();
    }
    finally
    {
        // Release the Mutex.
        mut.ReleaseMutex();
    }   

Upvotes: 1

Related Questions