Reputation: 22327
I'm writing an ASP.NET web application using C# that may read and write a text file from the IIS server (using System.IO.FileStream
) and I'm wondering how do I implement a global lock on this operation?
Upvotes: 4
Views: 5552
Reputation: 51
Named mutexes are systems objects. Unlike lock keywords, they work even across process boundaries. Lock is only useful in the context of synchronizing threads in same process.
Upvotes: 0
Reputation: 22327
From what @Aristos suggested and from this post, I came up with this class:
using System.Threading;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Runtime.InteropServices; //GuidAttribute
using System.Reflection; //Assembly
namespace ITXClimateSaverWebApp
{
public class GlobalNamedLock
{
private Mutex mtx;
public GlobalNamedLock(string strLockName)
{
//Name must be provided!
if(string.IsNullOrWhiteSpace(strLockName))
{
//Use default name
strLockName = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
}
//Create security permissions for everyone
//It is needed in case the mutex is used by a process with
//different set of privileges than the one that created it
//Setting it will avoid access_denied errors.
MutexSecurity mSec = new MutexSecurity();
mSec.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
MutexRights.FullControl, AccessControlType.Allow));
//Create the global mutex
bool bCreatedNew;
mtx = new Mutex(false, @"Global\" + strLockName, out bCreatedNew, mSec);
}
public bool enterCRITICAL_SECTION()
{
//Enter critical section
//INFO: May throw an exception!
//RETURN:
// = 'true' if successfully entered
// = 'false' if failed (DO NOT continue!)
//Wait
return mtx.WaitOne();
}
public void leaveCRITICAL_SECTION()
{
//Leave critical section
//INFO: May throw an exception!
//Release it
mtx.ReleaseMutex();
}
}
}
and then the way to call it for a global lock:
try
{
GlobalNamedLock gl = new GlobalNamedLock("MyLockName");
try
{
if (gl.enterCRITICAL_SECTION())
{
//Use the global resource now
}
}
finally
{
gl.leaveCRITICAL_SECTION();
}
}
catch (Exception ex)
{
//Failed -- log it
}
So this seems to do the job. What do you think?
Upvotes: 1
Reputation: 100358
Why don't just use global sync root object?
internal static class Lock
{
public static object SyncRoot = new object{};
}
Usage:
lock (Lock.SyncRoot)
{
}
Upvotes: 0
Reputation: 2942
The easiest solution would be to create a new object in the Cache or Application object, preferably in the Application_Startup within the global.asax file. Such as:
Cache["myLocker"] = new object();
Then you can use the standard "lock" syntax.
lock(Cache["myLocker"])
{
// do file access here...
}
Upvotes: 1
Reputation: 66649
For global lock you need 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();
// here you manipulate your file
}
finally
{
// Release the Mutex.
mut.ReleaseMutex();
}
Upvotes: 4