Suppose I write a C++ semaphore class with an interface that models the boost Lockable concept (i.e. lock(); unlock(); try_lock();
etc.). Is it safe/recommended to use boost locks for RAII access to such an object? In other words, do boost locks (and/or other related parts of the boost thread library) assume that the Lockable concept will only be modeled by mutex-like objects which are locked and unlocked from the same thread?
My guess is that it should be OK to use a semaphore as a model for Lockable. I've browsed through some of the boost source and it "seems" OK. The locks don't appear to store explicit references to this_thread or anything like that. Moreover, the Lockable concept doesn't have any function like whichThreadOwnsMe()
. It also looks like I should even be able to pass a boost::unique_lock<MySemaphore>
reference to boost::condition_variable_any::wait
. However, the documentation is not explicitly clear about the requirements.
To illustrate what I mean, consider a bare-bones binary semaphore class along these lines:
class MySemaphore{
bool locked;
boost::mutex mx;
boost::condition_variable cv;
public:
void lock(){
boost::unique_lock<boost::mutex> lck(mx);
while(locked) cv.wait(lck);
locked=true;
}
void unlock(){
{
boost::lock_guard<boost::mutex> lck(mx);
if(!locked) error();
locked=false;
}
cv.notify_one();
}
// bool try_lock(); void error(); etc.
}
Now suppose that somewhere, either on an object or globally, I have
MySemaphore sem;
I want to lock and unlock it using RAII. Also I want to be able to "pass" ownership of the lock from one thread to another. For example, in one thread I execute
void doTask()
{
boost::unique_lock<MySemaphore> lock(sem);
doSomeWorkWithSharedObject();
signalToSecondThread();
waitForSignalAck();
lock.release();
}
While another thread is executing something like
{
waitForSignalFromFirstThread();
ackSignal();
boost::unique_lock<MySemaphore>(sem,boost::adopt_lock_t());
doMoreWorkWithSameSharedObject();
}
The reason I am doing this is that I don't want anyone else to be able to get the lock on sem
in between the time that the first thread executes doSomeWorkWithSharedObject()
and the time the second executes doMoreWorkWithSameSharedObject()
. Basically, I'm splitting one task into two parts. And the reason I'm splitting the task up is because (1) I want the first part of the task to get started as soon as possible, (2) I want to guarantee that the first part is complete before doTask() returns, and (3) I want the second, more time-consuming part of the task to be completed by another thread, possibly chosen from a pool of slave threads that are waiting around to finish tasks that have been started by master threads.
NOTE: I recently posted this same question (sort of) here http://stackoverflow.com/questions/2754884/unlocking-a-mutex-from-a-different-thread-c but I confused mutexes with semaphores, and so the question about using boost locks didn't really get addressed.