Mutexes in .NET

The Mutex class in .NET is a little bit tricky to use.

Here’s an example how I got it to do what I want:

/// <summary>
/// A simple, cross application mutex. Use <see cref="Acquire"/> to acquire it
/// and release it via <see cref="Dispose"/> when you're finished.
/// </summary>
/// <remarks>
/// Only one thread (and thus process) can have the mutex acquired at the same
/// time.
/// </remarks>
public class SimpleMutex : IDisposable
{
    private readonly Mutex m_mutex;

    /// <summary>
    /// Acquires the mutex with the specified name.
    /// </summary>
    /// <param name="mutexName">the mutex's name</param>
    /// <param name="timeout">how long to try to acquire the mutex</param>
    /// <returns>Returns the mutex or <c>null</c>, if the mutex couldn't be
    /// acquire in time (i.e. the current mutex holder didn't release it in
    /// time).</returns>
    public static SimpleMutex Acquire(string mutexName, TimeSpan timeout)
    {
        var mutex = new SimpleMutex(mutexName);
        try
        {
            if (!mutex.m_mutex.WaitOne(timeout))
            {
                // We could not acquire the mutex in time.
                mutex.m_mutex.Dispose();
                return null;
            }
        }
        catch (AbandonedMutexException ex)
        {
            // We now own this mutex. The previous owner didn't
            // release it properly, though.
            Trace.WriteLine(ex);
        }

        return mutex;
    }

    private SimpleMutex(string mutexName)
    {
        this.m_mutex = new Mutex(false, mutexName);
    }

    public void Dispose()
    {
        this.m_mutex.ReleaseMutex();
        this.m_mutex.Dispose();
    }
}

You can use it like this:

using (SimpleMutex.Acquire("MyTestMutex", Timeout.InfiniteTimeSpan))
{
    Console.WriteLine("Acquired mutext");
    Console.ReadKey();
}

Console.WriteLine("Released mutext");

If you run your program twice, one will acquire the mutex and the other one will wait – until you press a key in the first one.

Note: If you forget to call Dispose() on this mutex, the operating system will make sure that the mutex is released when the program terminates. However, the next process trying to acquire this mutex will then get an AbandonedMutexException (which is handled properly in Acquire() though).

Windows Performance Counter Types

There are several types of performance counters in Windows. However, I had a hard time of understanding all these types just from their documentation. So I decided to compile some examples for each counter type.

I also wrote some C# code to demonstrate how to use performance counters. You’ll find it at the end of this article.

Read more →

Updating MAMP

MAMP

Working with MAMP is quite easy. However, the process of updating MAMP to a newer version might contain some uncertainties.

The following table contains things that one want to keep when upgrading to a newer version and whether they’re correctly migrated or not.

What Migrated
server ports (as specified in settings) no (tracked as #4796)
htdocs directory yes (moved)
htdocs location (as specified in settings) no (tracked as #4796)
Databases (db directory) yes (moved)

The process was tested with MAMP 3.0.7.3.

.NET Serializers Comparison Chart

There are many object serializers in C#/.NET but their details are often not so obvious, for example:

  • Does my class need a parameterless constructor?
  • Can I serialize private fields?
  • Can I serialize readonly fields?

So, I’ve compiled a comparison chart in this article that will compare the various serializers and their capabilities.

Read more →

Azure WAT150: This assembly is not in the package.

When publishing to Windows Azure, you may get the warning WAT150:

warning WAT150: The project ‘MyProject’ is dependent on the following assembly: J:\Sources\MyProject\packages\Microsoft.Data.Services.Client.5.6.0\lib\net40\Microsoft.Data.Services.Client.dll. This assembly is not in the package. To make sure that the role starts, add this assembly as a reference to the project and set the Copy Local property to true.

This warnings means that one of your projects uses an assembly that’s installed locally on your computer (e.g. using ASP.NET in a worker role) but is not installed on the Azure instance you want to run the package on. So, usually you can’t ignore this warning as the resulting package won’t run.

The usual fix is to use Nuget packages instead of globally installed assemblies. However, if this doesn’t work (like in my example above where the package clearly comes from Nuget), there’s another culprit:

The Global Assembly Cache (GAC)

Basically, if the referenced assembly is registered in the GAC with exactly the same version, then Visual Studio will always use the assembly from the GAC. Because of this, the assembly won’t be copied to the output directory and thus won’t be in the Azure package – resulting in WAT150 warnings.

This seems to be like this by design. Quoting from MSDN:

If you deploy an application that contains a reference to a custom component that is registered in the GAC, the component will not be deployed with the application, regardless of the CopyLocal setting. In previous versions of Visual Studio, you could set the CopyLocal property on a reference to ensure that the assembly was deployed. Now, you must manually add the assembly to the \Bin folder. This puts all custom code under scrutiny, reducing the risk of publishing custom code with which you are not familiar.

This statements is not entirely correct. Setting CopyLocal to true works – but only for the project directly referencing the assembly. Unfortunately, CopyLocal is not transitive, i.e. if project A references assembly X.dll (registered in the GAC; with CopyLocal set to true) and project B references project A, then X.dll will only appear in the output directory of project A but not in the output directory of project B. (It would appear in the output directory of project B if X.dll wasn’t in the GAC.)

How to fix

There are a couple of ways how to fix this problem, but they all are workarounds:

  • Delete the assembly from the GAC: Navigate to %WINDIR%\Microsoft.NET\assembly\GAC_MSIL and delete the assembly from here. Note though that these assemblies may still be need and some software may stop working.
  • Switch to a different assembly version that’s not in the GAC.
  • Reference the necessary assemblies directly in all role projects.