c00000fd
c00000fd

Reputation: 22327

How to add a global lock to ASP.NET web application?

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

Answers (5)

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

c00000fd
c00000fd

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

abatishchev
abatishchev

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

Tim P.
Tim P.

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

Aristos
Aristos

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

Related Questions