Asp.Net. Synchronization access(mutex)

2019-08-02 20:01发布

问题:

for synchronizing access to my NHibernate session at web environment I try use Mutex:

public class FactoryRepository
{
    private FactoryRepository() { }
    private static Mutex _sessionMutex = new Mutex();
    private static ISessionFactory factory;
    public static ISessionFactory SessionFactory
    {
        get
        {
            factory = factory ?? new Configuration().Configure().BuildSessionFactory();
            return factory;
        }
    }

    public static ISession Session
    {
        get
        {
            ISession currentSession;
            _sessionMutex.WaitOne();
            if (HttpContext.Current != null)
            {
                HttpContext context = HttpContext.Current;
                currentSession = context.Items[SessionKey] as ISession;
                if (currentSession == null || !currentSession.IsOpen)
                {
                    currentSession = SessionFactory.OpenSession();
                    context.Items[SessionKey] = currentSession;
                }
            }

            _sessionMutex.ReleaseMutex();
            return currentSession;

        }
    }
}

At my error logging I get:

System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
Method: Boolean WaitOne(Int64, Boolean)

Stack Trace:

 at System.Threading.WaitHandle.WaitOne(Int64 timeout, Boolean exitContext)
 at System.Threading.WaitHandle.WaitOne(Int32 millisecondsTimeout, Boolean exitContext)
 at System.Threading.WaitHandle.WaitOne()

Why do I get this exception with calling ReleaseMutex();

回答1:

Your issue is on this line

 _sessionMutex.WaitOne();

The WaitOne() can throw this exceptions because some other thread that lock it, exit with out releasing it

In your case the WaitOne throw this exception because of an abandon of the same mutex in an other thread.

I suggest to warp your mutex in a class and use a code like:

            try
            {
                cLock = _sessionMutex.WaitOne();
                // call your work
            }
            catch (AbandonedMutexException)
            {
                cLock = true;
                // call your work
            }
            catch (Exception x)
            {
                //Error
            }
            finally
            {
               _sessionMutex.ReleaseMutex();
            }

In the above code the ReleaseMutex may fail to run if a user stop/abandon the page and the thread is lost/delete it. And thats why you get this exception.

Be ware that mutex can lock for ever the way you do it ! :) Its better to add a millisecond limit on the wait, and / or handle the case of non lock to return read only data. You users can lock for long time if the mutex fails to pass the WaitOne()

Also be ware, the Mutex need to be close and dispose. ! Even if this is like the example in MSDN, in MSDN is only an simple Example, you need to be sure that you close and dispose your Mutex or else you see more problems when you update your page. For example if the Mutex stay on memory locked wile you update your page, then your page may lock for long time, until the Garbage collection kill it, if they do.



回答2:

Unless you're using a very old version of NHibernate, I think this is probably overkill. NHibernate already has the ability to give you contextual session management in a web environment, and I think it will manage things more reliably for you.

Take a look at section 2.3 of this: NHibernate Chapter 2 - Architecture



回答3:

Windows O/S has long had a bug where locking one mutex inside another could lock both if they are not unlocked properly in the correct reverse sequence.

Basically the race condition and locking could be due to NHibernate using a mutex to lock the resource as well as the mutex you are using.