C # - Problems with locking using Mutex

I have a web application that controls which web applications receive served traffic from our load balancer. The web application runs on each individual server.

It tracks the entry or exit state for each application in the object in the ASP.NET application state, and the object is serialized to a file on disk whenever the state changes. The state is deserialized from the file when the web application starts.

While the site itself receives a couple of requests at the second top and a file that it rarely accesses, I found that for some reason it was very easy to get collisions when trying to read or write to a file. This mechanism must be extremely reliable, because we have an automated system that regularly performs deployment deployments on the server.

Before anyone makes any comments questioning the prudence of any of the above, let me just say that explaining the reasons why it would have made this message much longer than it is, so I would like to avoid moving mountains.

However, the code I use to control access to the file is as follows:

internal static Mutex _lock = null;
/// <summary>Executes the specified <see cref="Func{FileStream, Object}" /> delegate on 
/// the filesystem copy of the <see cref="ServerState" />.
/// The work done on the file is wrapped in a lock statement to ensure there are no 
/// locking collisions caused by attempting to save and load the file simultaneously 
/// from separate requests.
/// </summary>
/// <param name="action">The logic to be executed on the 
/// <see cref="ServerState" /> file.</param>
/// <returns>An object containing any result data returned by <param name="func" />. 
///</returns>
private static Boolean InvokeOnFile(Func<FileStream, Object> func, out Object result)
{
    var l = new Logger();
    if (ServerState._lock.WaitOne(1500, false))
    {
        l.LogInformation( "Got lock to read/write file-based server state."
                        , (Int32)VipEvent.GotStateLock);
        var fileStream = File.Open( ServerState.PATH, FileMode.OpenOrCreate 
                                  , FileAccess.ReadWrite, FileShare.None);                
        result = func.Invoke(fileStream);                
        fileStream.Close();
        fileStream.Dispose();
        fileStream = null;
        ServerState._lock.ReleaseMutex();
        l.LogInformation( "Released state file lock."
                        , (Int32)VipEvent.ReleasedStateLock);
        return true;
    }
    else
    {
        l.LogWarning( "Could not get a lock to access the file-based server state."
                    , (Int32)VipEvent.CouldNotGetStateLock);
        result = null;
        return false;
    }
}

, ( " " ). - (Win Server 2k3/IIS 6). -, ( ?), .

, , , .

Application_Start. , .

, : / - , .

, ?


Update:

( !), - .

- - - , . , , - , WP , , , , , .

@mmr: Monitor, Mutex? MSDN, , - Mutex, , false.

: , , - , . , (, , ).


2:

. , _lock InvokeOnFile, .

Func - , , . .

ServerState.PATH - readonly, , concurrency.

, ( Cassini).


:

  • (duh!)
  • ( , / ). , Mutex, -, , , Monitor .NET.
+3
3

, -.

, , .NET Framework . , Mutex class Win32 . , interop, , Monitor.

, .

, , , Mutex . , , , , , .

, 1,5 , , Mutexes . .

, , . , , , , . .

, :

// if you want timeout support use 
// try{var success=Monitor.TryEnter(m_syncObj, 2000);}
// finally{Monitor.Exit(m_syncObj)}
lock(m_syncObj)
{
    l.LogInformation( "Got lock to read/write file-based server state."
                    , (Int32)VipEvent.GotStateLock);
    using (var fileStream = File.Open( ServerState.PATH, FileMode.OpenOrCreate
                                     , FileAccess.ReadWrite, FileShare.None))
    {
        // the line below is risky, what will happen if the call to invoke
        // never returns? 
        result = func.Invoke(fileStream);
    }
}

l.LogInformation("Released state file lock.", (Int32)VipEvent.ReleasedStateLock);
return true;

// note exceptions may leak out of this method. either handle them here.
// or in the calling method. 
// For example the file access may fail of func.Invoke may fail
+15

, . , . try/catch finally.

, Global.asax Application_Start, , ( , , ?). .., ( , ), 1 , .

. , , , , .

+2

.

2: /, : "", - "". . , . Invoke - , , "" "".

1) LogInformation? , , . , / , . , .

2) , Monitor, , , #, , ASP.NET. . - . ( : . ; , - , - , .NET. . .)

3) , , - ? , , (.. - , , ).

4) ? , ? ServerState.PATH?

5) ServerState._lock? , , , /. , , , - - . , , - . ( , , , - - , ).

    Object MyLock = new Object();
    private static Boolean InvokeOnFile(Func<FileStream, Object> func, out Object result)
{
    var l = null;
    var filestream = null;
    Boolean success = false;
    if (Monitor.TryEnter(MyLock, 1500))
        try {
            l = new Logger();
            l.LogInformation("Got lock to read/write file-based server state.", (Int32)VipEvent.GotStateLock);
            using (fileStream = File.Open(ServerState.PATH, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)){                
                result = func.Invoke(fileStream); 
            }    //'using' means avoiding the dispose/close requirements
            success = true;
         }
         catch {//your filestream access failed

            l.LogInformation("File access failed.", (Int32)VipEvent.ReleasedStateLock);
         } finally {
            l.LogInformation("About to released state file lock.", (Int32)VipEvent.ReleasedStateLock);
            Monitor.Exit(MyLock);//gets you out of the lock you've got
        }
    } else {
         result = null;
         //l.LogWarning("Could not get a lock to access the file-based server state.", (Int32)VipEvent.CouldNotGetStateLock);//if the lock doesn't show in the log, then it wasn't gotten; again, if your logger is locking, then you could have some issues here
    }
  return Success;
}
0
source

All Articles