Reputation: 204
I have a C++ program in a Win32 device. The code has function X that should block other calls to X. That's simple enough, I can use a mutex to do that.
Function X, however, creates and launches a thread, Y, that will monitor things after X has finished. I need to ensure that X cannot run again until Y is satisfied that everything is finished properly.
As I understand it, a mutex can only be acquired and released on the same thread. What I'd like to do is to hand over the 'locked-ness' of the mutex from X to Y.
If it's easier to picture this in terms of what actually happens, X is there to print something, Y is there to check that the print job completes without running out of paper. Once Y is satisfied that the job has completed and the paper has not run out then it can let X print something else. We want X to finish ASAP so that the device can get on with other work (which will usually not involve printing, and therefore should not be held up while the printer finishes.)
So... is there a standard cross-thread locking pattern that will do what I want to do?
I can't use boost or any other third party libraries, only Windows built-in operations.
Upvotes: 1
Views: 655
Reputation: 204
I marked Harry Johnston's answer as accepted because it sounds like it will do the job fine, and seems a good generic solution. And I may even use it.
What I have done for now is to replace the single mutex with two critical section objects, let's calls them CSx and CSy. Entry to X depends on entering CSx. Once that is done, X also enters CSy. It then immediately leaves CSy, and this is because when thread Y is launched it will enter CSy for the duration of its life. The only reason X enters CSy (and leaves it immediately) is because that's how it knows that thread Y is not running from a previous call to X.
This is similar to Erik's comment, above, but instead of tracking a single thread handle it allows multiple X and Y to queue up.
The risk here is that thread Y may not enter CSy before function X leaves CSx, so there is scope for another X to get in first, though the circumstances of the device and what it is doing means that this won't actually happen.
Even so, Harry's solution has the benefit of a single locking object and the simplicity and elegance that this brings.
Upvotes: 0
Reputation: 36348
That's a simple enough scenario. All you need to do is replace the mutex with an auto-reset event, initially signaled.
An auto-reset event can be used in the same way as a mutex (subject to some provisos, see below) but can be released by any thread:
There are a few differences between mutex objects and event objects that you should be aware of:
Unlike a mutex, an auto-reset event does not allow recursive entry by the same thread. So if function X calls itself you'll need to rearrange the code slightly, so that acquiring the lock happens outside of the recursion.
Unlike a mutex, the API will not generate an error if the thread that "owns" an event exits unexpectedly. So if Y were to exit without signaling the event, the application will deadlock. If this is a problem, you will need to monitor the status of thread Y yourself. (And, of course, the same reasoning applies to the thread calling X, if it exits before launching Y.)
Upvotes: 2
Reputation: 149155
I would reverse the order of threads :
That way allows you to lock and release the mutex in same thread. In addition you get a nicer separation of concerns :
Upvotes: 0