2

I've looked through SO for this issue, but the other instances seem to relate only to multi-threaded app issues.

My app is a straightforward single-form, single-thread app and I'm just using a mutex to ensure only one instance is run on the host system.

Here is my code:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace UPGRADE
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Mutex mSpartacus;

            Assembly myAssembly = Assembly.GetExecutingAssembly();
            GuidAttribute ga = (GuidAttribute)myAssembly.GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0);
            string sMyGUID = ga.Value.ToString().ToUpper();
            string sMutexId = @"Global\{" + sMyGUID + @"}";

            bool bMutexAcquired = false;
            mSpartacus = new Mutex(false, sMutexId, out bMutexAcquired);
            if (!bMutexAcquired)
            {
                MessageBox.Show("Upgrade.exe is already running.\n\nOnly one instance can run at once.", "Already running");
                return;
            }

            try
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Form1 myForm = new Form1();
                Application.Run(myForm);
            }
            finally
            {
                mSpartacus.ReleaseMutex();
            }
        }
    }
}

It fails on the ReleaseMutex() call with the error Object synchronization method was called from an unsynchronized block of code.

Can someone explain what I'm doing wrong? The mutex was originally a static variable, but putting it inside the Main() function didn't stop the error occurring.

TonyLongson
  • 121
  • 1
  • 5

2 Answers2

5

As read from the msdn, you should pass true on the initiallyOwned parameter.

https://msdn.microsoft.com/en-us/library/bwe34f1k(v=vs.110).aspx

mSpartacus = new Mutex(true, sMutexId, out bMutexAcquired);

Because the first instance of the application wants to have the ownership (so other instances of the same program, can't have it). If you don't have the ownership, you can't release it. If you can't have the ownership, because another instance is already acquired it, the bMutexAcquired returns false.


If you pass false to the initiallyOwned parameter. You are only creating the mutex. Then you must use WaitOne() to acquire (lock) the mutex and ReleaseMutex() to release it.

Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
1

You have to acquire the Mutex. There are two way to acquire the Mutex:

  • Using WaitOne method
  • Using the constructor argument initiallyOwned

Here's an example using the WaitOne method:

const string AppId = "Global\\1DDFB948-19F1-417C-903D-BE05335DB8A4"; // Unique per application 
static void Main(string[] args) 
{ 
   using (Mutex mutex = new Mutex(false, AppId)) 
   { 
       if (!mutex.WaitOne(0)) 
       { 
           Console.WriteLine("2nd instance"); 
           return; 
       } 
       Console.WriteLine("Started"); 
       Console.ReadKey(); 
   } 
}
meziantou
  • 20,589
  • 7
  • 64
  • 83