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 Modelling boost::Lockable with semaphore rather than mutex (previously titled: Unlocking a mutex from a different thread) but I confused mutexes with semaphores, and so the question about using boost locks didn't really get addressed.
lockfunction of Lockable, and the pre-condition for theunlockfunction, are that this thread "owns" the lock. So although there's no function to return the owning thread, Lockable is defined in those terms. Now, there's nothing to say that a Lockable object can't have another function to transfer ownership of the lock atomically from one thread to another, so I don't think you're violating the contract of Lockable to do this. Actually implementing that atomic transfer of ownership is going to be tricksy, depending how reliable you want it to be. - Steve Jessopunique_lockand transfer ownership of your lock during the lifetime of that object, then you're in the same state of sin as if you used aunique_lockand calledunlockduring the lifetime. You're messing with the contract ofunique_lock, which is that it manages ownership of the Lockable, and you leave it to do so. - Steve Jessoplockis followed by exactly one call tounlock(from any thread). Or, put a different way, whenever any thread callsunlock, I could implicitly transfer ownership to the unlocking thread, without actually doing anything. It seems to me that this behavior is indistinguishable from physically transferring ownership. - dan