Sergey Sokolov
Sergey Sokolov

Reputation: 139

Using mutex to ensure single instance for asynchronous app

I'm trying to use C# mutex to ensure my application is running in single instance. So, the application is acquiring global mutex on start, and releasing it on exit. If the mutex acquisition is failed, the error is shown. The application is a console app and it's mostly asynchronous (Main method is async). Basically, the mutex is acquired at the beginning of Main method, and released at the end of it. The problem is that the Main method being asynchronous, its ending may be executed on a different thread than the beginning. So, when I try to release the mutex, I get "Object synchronization method was called from an unsynchronized block of code" exception because the mutex cannot be released from another thread. But I don't use the mutex for inter-thread synchronyzation, I use it for inter-process synchronization. So I don't really care which thread releases the mutex since it's guaranteed that acquire and release are not conflicting with each other. I know there are two ways to avoid this error:

Both of these ways seem too cumbersome. Is there a better way to ensure single instance for async app?

Upvotes: 2

Views: 2609

Answers (2)

Theodor Zoulias
Theodor Zoulias

Reputation: 43758

You could use a synchronous Main entry point. For a console application, blocking the startup thread is not a big deal. Unlike GUI applications, this thread has nothing to do while asynchronous operations are carried out. This is what happens anyway when you use an async Task Main as entry point.

public static void Main(string[] args)
{
    var mutex = new Mutex(false, Assembly.GetEntryAssembly().GetName().Name);
    if (!mutex.WaitOne(0))
    {
        Console.WriteLine($"Already running. Press any key to continue . . .");
        Console.ReadKey();
        Environment.Exit(1);
    }
    try
    {
        MainAsync(args).GetAwaiter().GetResult();
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

public static async Task MainAsync(string[] args)
{
    // Main body here
}

Btw you should check out this question about a possible race condition, that could result to an AbandonedMutexException. I guess that the race condition is subtle, because I wasn't able to reproduce it.

Upvotes: 4

Stephen Cleary
Stephen Cleary

Reputation: 456917

While you could use either of the approaches you mention, it would probably just be simpler to use a named semaphore instead of a named mutex.

Unlike mutexes, semaphores do not care which threads release them.

Upvotes: 3

Related Questions