0

I have a situation where I need to have only one instance of a program running at the same time.

This would be trivial like this:

class OneAtATimePlease
{
  static void Main()
  {
    // Naming a Mutex makes it available computer-wide. Use a name that's
    // unique to your company and application (e.g., include your URL).

    using (var mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"))
    {
      // Wait a few seconds if contended, in case another instance
      // of the program is still in the process of shutting down.

      if (!mutex.WaitOne (TimeSpan.FromSeconds (3), false))
      {
        Console.WriteLine ("Another app instance is running. Bye!");
        return;
      }
      RunProgram();
    }
  }

  static void RunProgram()
  {
    Console.WriteLine ("Running. Press Enter to exit");
    Console.ReadLine();
  }
}

Except for the small detail, that I need the EXISTING process to terminate, not the new one.

I tried making a semaphore the existing process could listen to after grabbing the above mutex, but because I want it to wait for the semaphore then I can end up in a situation where the semaphore is always signaled and thus it doesn't work.

Anyone have a good idea on how to solve this problem?

mu is too short
  • 426,620
  • 70
  • 833
  • 800
Cine
  • 4,255
  • 26
  • 46
  • If this is C#, try this: http://www.codeproject.com/Articles/4430/Single-Instance-Application-in-C – tjg184 Jul 03 '12 at 03:28
  • Doesn't matter, even if you give me a working example in ML I will still figure it out :) – Cine Jul 03 '12 at 03:28

3 Answers3

1

You need inter-process communication, to send a signal to the existing application. For C#, see IPC Mechanisms in C# - Usage and Best Practices.

Community
  • 1
  • 1
sourcenouveau
  • 29,356
  • 35
  • 146
  • 243
1

Cine, I've written a two-Mutex logic. The first one is the "execution lock", while the second is the "monitor lock". When the first process can't acquire the monitor lock, it will exit and release the execution lock for the new process.

I'm not sure if this is the best solution, and any feedback will be welcome.

C#:

class Program
    {
        private static string processName = DateTime.Now.ToString("hh.mm.ss");
        private static bool exitProcess;

        private static Mutex firstLock
        {
            get
            {
                return new Mutex(false, "stackoverflow.com/questions/11304052/");
            }
        }

        private static Mutex secondLock
        {
            get
            {
                return new Mutex(false, "stackoverflow.com/questions/11304052/ #2");
            }
        }


        static void Main(string[] args)
        {
            Console.WriteLine(string.Format("Process {0} starting", processName));

            exitProcess = false;

            while (true)
            {
                using (firstLock)
                {
                    Console.WriteLine(string.Format("Process {0} trying to get #1 mutex", processName));

                    if (!firstLock.WaitOne(TimeSpan.FromSeconds(1), false))
                    {
                        Console.WriteLine(string.Format("Process {0} #1 mutex in use, waiting for release", processName));

                        bool killFirstApp = false;

                        while (!killFirstApp)
                        {
                            killFirstApp = LockSecondMutex();
                        }

                        continue;
                    }

                    new Thread(MonitorSecondMutex).Start();

                    RunProgram();

                    firstLock.ReleaseMutex();

                    break;
                }
            }
        }

        static void RunProgram()
        {
            while (!exitProcess)
            {
                Console.WriteLine(string.Format("Process {0} running", processName));

                Thread.Sleep(1000);
            }
        }

        static void MonitorSecondMutex()
        {
            while (true)
            {
                using (secondLock)
                {
                    if (!secondLock.WaitOne(TimeSpan.FromSeconds(2), false))
                    {
                        Console.WriteLine(string.Format("Process {0} lost second mutex. Will now exit.", processName));

                        exitProcess = true;

                        break;
                    }

                    secondLock.ReleaseMutex();
                }

                Thread.Sleep(500);
            }
        }

        static bool LockSecondMutex()
        {
            while (true)
            {
                using (secondLock)
                {
                    if (!secondLock.WaitOne(TimeSpan.FromSeconds(2), false))
                    {
                        continue;
                    }

                    Thread.Sleep(5000);

                    secondLock.ReleaseMutex();
                }

                return true;
            }
        }
    }
Andre Calil
  • 7,652
  • 34
  • 41
  • Ugh, a spinwait? But otherwise a nice solution – Cine Jul 03 '12 at 07:53
  • I tried handling an event with the Mutex, but I don't know if that's possible. It's kind of a spin-wait, but as it does not occurs on the main thread, I thought it could be of some use. Copy the code and give a try, I'd like to see your improvement on this idea =) – Andre Calil Jul 03 '12 at 11:21
0

You could possibly get this done by requesting access to some limited system-wide resource, such as port. Your application could bind a socket to a specific port on launch. If it fails to bind, send a termination signal to the running instance and try again.

Connor Doyle
  • 1,812
  • 14
  • 22