Click here to Skip to main content
13,832,908 members
Click here to Skip to main content
Add your own
alternative version


28 bookmarked
Posted 6 Aug 2004
Licenced CPOL

An interruptible mutex class

, 6 Aug 2004
Rate this:
Please Sign up or sign in to vote.
How to safely terminate a thread waiting on a mutex
<!-- Add the rest of your HTML here -->


As developers we're rightly concerned that our applications keep running. So concerned, in fact, that it's easy to forget that a user will judge our work not just by how well it runs but also by how easily they can stop it running. Dunno about you but when I hit the close button on an application I expect it to go away now. It's acceptable that it ask me if I want to save changes I've made but it's not acceptable that it just hangs around, seemingly indefinitely. Even if the UI goes away I'll probably notice the app is still there in task manager if it takes a while to exit. (In passing I note that Visual Studio sometimes seems to take forever to terminate - hanging around long after the UI has been torn down. Interestingly enough, when it does this it consumes almost no CPU cycles. What follows is part of my educated guesses as to the reason why).


Much of the work I've been doing lately involves multiple threads. I've already covered, in other articles, some of the issues involved with using threads whilst being able to stop them at will, such as using overlapped I/O[^] in order to make an I/O thread stoppable and the need to make sure a thread is cognizant of external events in this article[^ ].

Recently I ran into another issue with stopping threads. The issue involved synchronising access to a shared resource.

Sharing resources

We all know the theory. If two or more threads are sharing a resource they should implement some kind of mediation mechanism in order to be sure that changes made by a thread are completed and the shared resource returns to a stable state before another thread gains access. For example, if one thread is adding records to the tail of a linked list it's probably not a good idea to have another thread simultaneously removing records from the head of that linked list. That way memory corruption lies! Thus it behooves the careful programmer to implement locking around the operations on the linked list. Thread A aquires the lock or waits until it can aquire the lock. Once it's got the lock it performs the work it needs to do on the linked list and then releases the lock. If Thread B wants to perform operations on the linked list while Thread A has the lock it waits until the lock is released. Once the lock is released thread B has a chance to grab the lock and do it's work.


One way to implement the mediation mechanism is to use a mutex. The name is a contraction of mutual exclusion. One entity, and one entity alone, can own a mutex. If you own a mutex no one else can own it. As long as someone else owns it you can't. If everyone who wants to perform work on a shared resource agrees that such work can only be done when a mutex protecting the shared resource is owned by that worker the problem is solved.

You create a mutex on the Windows platform by calling the CreateMutex function, which returns a handle to a mutex object. You aquire ownership of the mutex either by specifying that you own it when you create it, or by waiting on it. If the mutex isn't owned by anyone else when you wait on it you get ownership, otherwise you wait until it's been released by the owner. And finally, when you've finished with owning the mutex you release it.

The problem

If you've read my article about using overlapped I/O you know what the problem is. The problem is that the classic way of waiting on a mutex is to use WaitForSingleObject() which, as the name suggests, waits on a single object (the mutex handle). The wait is, of course, done deep in the bowels of the operating system in code you didn't write and don't control. There are only two ways for the call to return. Either the object is signalled (we gained ownership of the mutex) or the timeout has elapsed. I might write a thread thusly,

<PRE lang=c++>unsigned __stdcall ThreadProc(LPVOID data) { // Cast data to some type relevant to the context // and do some preliminary work. Then grab the mutex. WaitForSingleObject(gbl_hMutex, INFINITE); // Now we've got the mutex, do some work and then release it. ReleaseMutex(gbl_hMutex); }

Now obviously this thread procedure makes no provision for the possibility that it might need to be externally terminated. The only way you're going to kill this thread, once it's waiting on the mutex, is to make sure the mutex is released so this thread can gain ownership of it (and thus break out of the WaitForSingleObject()) call, or use TerminateThread(), which is a course fraught with problems unless you're terminating the entire process. What if you want to terminate only this thread yet keep the entire process running?

The first approach might be to do something like this.

<PRE lang=c++>unsigned __stdcall ThreadProc(LPVOID data) { bool bStayInLoop = true; while (bStayInLoop) { // Do some preliminary work then grab the mutex switch (WaitForSingleObject(gbl_hMutex, 100)) { case WAIT_OBJECT_0: // We got the mutex, break out of the while loop bStayInLoop = false; break; case WAIT_TIMEOUT: // We timed out, check if we should terminate the // thread. if (gbl_exitThread) // It's terminate time, exit the thread return 0; } } // Now we've got the mutex, do some work and then release it. ReleaseMutex(gbl_hMutex); } which waits a short time for the mutex, times out if it didn't get the mutex, checks if it should exit and if not repeats the entire process. This takes a some educated guessing to get it right. Set the timeout too low and you waste CPU cycles checking if your thread should exit. Set the timeout too high and the thread takes too long to terminate itself.

A better approach

is to use the WaitForMultipleObjects() call passing two handles. One handle is the handle to the mutex you want to own, the other handle is to an event object which can be signalled when you want the thread to terminate. The code would look something like this.

<PRE lang=c++>unsigned __stdcall ThreadProc(LPVOID data) { // Do some preliminary work then grab the mutex HANDLE hArray[2] = { gbl_stopEvent, gbl_hMutex }; switch (WaitForMultipleObjects(2, hArray, FALSE, INFINITE)) { case WAIT_OBJECT_0: // We've been signalled to exit, so exit return 0; case WAIT_OBJECT_0 + 1: // We got the mutex break; } // Now we've got the mutex, do some work and then release it. ReleaseMutex(gbl_hMutex); }

Now you can wait for the mutex to become available, safely terminate the thread when requested and do both without wasting any CPU cycles. Naturally I want to encapsulate at least part of this into a class I can reuse.


Is a class that handles the creation and destruction of the mutex and performs the wait on your behalf. The class looks like this. <PRE lang=c++>class CInterruptibleMutex { public: enum eMutexState { eStopped, eMutexAquired, eTimedOut, }; CInterruptibleMutex(); virtual ~CInterruptibleMutex(void); bool IsValid() const { return m_hMutex != INVALID_HANDLE_VALUE; } eMutexState AquireMutex(HANDLE hStopEvent, DWORD dwTimeout = INFINITE); void ReleaseMutex() const { ::ReleaseMutex(m_hMutex); } private: HANDLE m_hMutex; };

which looks pretty straightforward. The constructor creates the mutex object, initially unowned by anyone. The destructor closes the mutex handle. The IsValid() function can be used to check that it was possible to create the mutex object controlled by the class. This will only fail if Windows was unable to allocate a handle, and if that's the case your program probably has little chance of running successfully anyway!

AquireMutex() takes a handle to an event which is used to interrupt the call if required; You can specify a timeout that defaults to INFINITE.

The AquireMutex() function looks like this. <PRE lang=c++>CInterruptibleMutex::eMutexState CInterruptibleMutex::AquireMutex( HANDLE hStopEvent, DWORD dwTimeout) { assert(IsValid()); HANDLE hArray[2] = { hStopEvent, m_hMutex }; switch (WaitForMultipleObjects(2, hArray, FALSE, dwTimeout)) { case WAIT_OBJECT_0: return eStopped; case WAIT_OBJECT_0 + 1: return eMutexAquired; default: return eTimedOut; } } which creates a handle array and calls WaitForMultipleObjects() . The call returns the appropriate value from the eMutexState enumeration so that calling code can determine an appropriate course of action. Pretty simple.

Using the code

Add the files in the download to your project and then instantiate a CInterruptibleMutex object where you'd normally use a HANDLE to a mutex. Create an event object somewhere in your code and make sure it's a manual reset event. Then call the AquireMutex() function passing the event handle. If you need to terminate the AquireMutex() call before it aquires ownership of the mutex you signal the event handle. Of course, the calling function has to take account of the return value from AquireMutex() but most of my usage of the class has specified an infinite timeout so I never need worry about the possibility of it returning eTimedOut (I should live so long...). Thus, in the usual case, a call to AquireMutex() can be as simple as,

<PRE lang=c++>if (m_myMutex.AquireMutex(m_hStopEvent) == CInterruptibleMutex::eStopped) // We were stopped, exit the thread return 0;


August 7th, 2004 - Initial version


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Rob Manderson
United States United States
I've been programming for 35 years - started in machine language on the National Semiconductor SC/MP chip, moved via the 8080 to the Z80 - graduated through HP Rocky Mountain Basic and HPL - then to C and C++ and now C#.

I used (30 or so years ago when I worked for Hewlett Packard) to repair HP Oscilloscopes and Spectrum Analysers - for a while there I was the one repairing DC to daylight SpecAns in the Asia Pacific area.

Afterward I was the fourth team member added to the Australia Post EPOS project at Unisys Australia. We grew to become an A$400 million project. I wrote a few device drivers for the project under Microsoft OS/2 v 1.3 - did hardware qualification and was part of the rollout team dealing directly with the customer.

Born and bred in Melbourne Australia, now living in Scottsdale Arizona USA, became a US Citizen on September 29th, 2006.

I work for a medical insurance broker, learning how to create ASP.NET websites in VB.Net and C#. It's all good.

Oh, I'm also a Kentucky Colonel.

You may also be interested in...

Comments and Discussions

GeneralThat's all what I want Pin
Sahbi19-Jan-05 5:20
memberSahbi19-Jan-05 5:20 
GeneralA different approach Pin
Toby Opferman8-Aug-04 16:23
memberToby Opferman8-Aug-04 16:23 
GeneralOnly advantage of mutexes? Pin
Nathan Holt at EMOM17-Aug-04 6:57
memberNathan Holt at EMOM17-Aug-04 6:57 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman18-Aug-04 5:54
memberToby Opferman18-Aug-04 5:54 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM18-Aug-04 6:51
memberNathan Holt at EMOM18-Aug-04 6:51 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman18-Aug-04 8:52
memberToby Opferman18-Aug-04 8:52 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman18-Aug-04 9:00
memberToby Opferman18-Aug-04 9:00 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM19-Aug-04 7:10
memberNathan Holt at EMOM19-Aug-04 7:10 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman19-Aug-04 14:03
memberToby Opferman19-Aug-04 14:03 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM20-Aug-04 6:04
memberNathan Holt at EMOM20-Aug-04 6:04 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman21-Aug-04 8:46
memberToby Opferman21-Aug-04 8:46 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman21-Aug-04 9:28
memberToby Opferman21-Aug-04 9:28 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM23-Aug-04 7:15
memberNathan Holt at EMOM23-Aug-04 7:15 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman23-Aug-04 16:10
memberToby Opferman23-Aug-04 16:10 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM26-Aug-04 7:12
memberNathan Holt at EMOM26-Aug-04 7:12 
GeneralRe: Only advantage of mutexes? Pin
Toby Opferman26-Aug-04 18:47
memberToby Opferman26-Aug-04 18:47 
GeneralRe: Only advantage of mutexes? Pin
Nathan Holt at EMOM1-Sep-04 7:39
memberNathan Holt at EMOM1-Sep-04 7:39 
GeneralSubject name is a bit misleading Pin
sgenie8-Aug-04 12:41
membersgenie8-Aug-04 12:41 
GeneralRe: Subject name is a bit misleading Pin
Rob Manderson8-Aug-04 13:10
protectorRob Manderson8-Aug-04 13:10 
GeneralRe: Subject name is a bit misleading Pin
sgenie8-Aug-04 13:18
membersgenie8-Aug-04 13:18 
GeneralRe: Subject name is a bit misleading Pin
Rob Manderson8-Aug-04 14:06
protectorRob Manderson8-Aug-04 14:06 
GeneralRe: Subject name is a bit misleading Pin
sgenie8-Aug-04 14:12
membersgenie8-Aug-04 14:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190114.1 | Last Updated 7 Aug 2004
Article Copyright 2004 by Rob Manderson
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid