Reputation: 2276
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
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
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:
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
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