January 1998

Use a mutex to achieve synchronization

by Sam Azer

Over the past few months, a few people on the CPB-Thread listserv have asked how to prevent more than one instance of an application from being started. (To subscribe to CPB-Thread, visit www.cobb.com/cpb.) Several people have worked very hard on a variety of answers to this question. It seems, though, that the simplest solution is one suggested by members of Borland's TeamB on their news server: a named mutex. As you know, Windows 95 provides a number of built-in functions for running multiple tasks and threads within a task. Accordingly, a group of Synchronization functions is available to ensure that your tasks and threads are able to work together effectively.

One of the more common problems in a multitasking environment is resource sharing. If you're using a resource--for example, a serial port--you don't want somebody else to start using it before you're finished. The standard solution to this problem is for you to get a mutual exclusion lock (mutex) on the resource. If you're able to get the lock, you can use the resource. If, while trying to lock the resource, you find that somebody else has it--you must wait.

In this article, we'll build a small and very simple function to return true if an instance of a program is already running. To do this, we'll use a simple named mutex. (You can download the code from this article at www.cobb.com/cpb.) Let's start by looking at how you can use a mutex.

 

Using a named mutex

A mutex is a very simple object. It has a name, access rights, and a state. The name must be unique among all mutex, semaphore, and file-mapping objects. In most cases, the access rights will be MUTEX_ALL_ACCESS. The state can be Owned or Not Owned. If you create a resource that can be used by only one caller at a time, you'll probably also create a mutex for it. In this case, your callers try to open the mutex to see if the resource exists. Once they have a valid handle to the mutex, they use wait functions to gain ownership of the resource and start using it. Wait functions sleep until a mutex isn't owned, then take ownership of it and use the resource. (You can optionally place a time limit on a wait function.) Eventually, the caller will release the mutex, marking it not owned and available to the next caller. In this way, all callers wait to take ownership of the resource when they need it and release it when they're finished. If a caller has no further need for a resource, the mutex handle can be closed.

Once a mutex exists, any tasks trying to create it again will get a handle to it and an error already exists error. If a task ends, all the mutex handles that it owns are closed. When all tasks have closed their handles to a mutex, it's destroyed. Therefore, a single call to the CreateMutex() function is all you need to find out if an instance of an application is already running!

Using CreateMutex()

The CreateMutex() function takes only three parameters: a pointer to a security descriptor, a flag to request immediate ownership, and the name of the mutex to create. It returns a HANDLE. It ignores the pointer to the security descriptor under Windows 95. Under Windows NT, you can get default security settings by passing a NULL pointer. The mutex name is simply any unique null-terminated string (up to MAXPATH characters in length). If the returned HANDLE is null, something undesirable happened. In any case, GetLastError() should return zero to indicate that the mutex was created. A value of ERROR_ALREADY_EXISTS indicates that the mutex already exists. Use SysErrorString() to translate the other error codes into English.

By now you've probably realized that there really isn't much to it--you can very easily detect an existing instance of an application using this method. Listing A shows the source code for one way to do it.

Listing A: Detecting another instance of an application

//---------------------------------
	-----------#include <vcl\vcl.h>
#pragma hdrstop 
//--------------------------------
	------------USEFORM("OneOnlyForm.cpp", Form1);
USERES("OneOnly.res"); 
//--------------------------------
	------------// the name of the mutex for this program
const char *MutexName = "OneOnlyDemo";
//---------------------------
	-----------------HANDLE 
		CheckInstance( const char *Name )
{
   // 1st: create mutex. Request ownership.
   HANDLE Mutex = CreateMutex(NULL,true,Name);
   // Next, error result - should be zero
   int r = GetLastError();
   // if r != 0, probably ERROR_ALREADY_EXISTS
   if ( r != 0 ) 
      return 0; // disaster or another instance
   return Mutex; // else, return the handle.
}
//----------------------------
	----------------WINAPI WinMain
		(HINSTANCE,HINSTANCE,LPSTR, int)
{
   HANDLE Mutex = CheckInstance( MutexName );
   if ( !Mutex )
   {  MessageBox(HInstance,
"Another Instance is running!",
"Sorry", MB_OK );
      ReleaseMutex( Mutex );
      return 1;
   };

   try
   {
      Application->Initialize(); 
      Application->CreateForm(__classid(
        TForm1),&Form1);
      Application->Run();
   }
   catch (Exception &exception)
   {
      Application->ShowException(&exception);
   }
   return 0;
}
//--------------------------------------------

Wrap up

Do a keyword search for Synchronization in the Win32 (Platform) SDK Help files for detailed information on the functions available for synchronizing--they're quite handy. In many cases the code presented in this article is enough to prevent problems from occurring between two instances of a simple database program. However, for MDI applications you'll probably want to send a message to the original instance. Watch for an article on inter-process communications in a future issue of C++Builder Developer's Journal.