Answer.. Don't take the examples at their face value
Likewise.
you can do this:
class counter { public: counter() : guard(this->mutex) { this->count = 0; this->guard.unlock(); } void lock() { guard.lock(); } int increment() { assert(this->guard.locked()); return ++count; } void unlock { assert(!this->guard.locked()); this->guard.unlock(); } // ..Nothing to do here.. // ~counter() { // }
private: boost::mutex mutex; boost::mutex::scoped_lock guard; int count; };
This is not equivalent to the above scenario. You can't have two threads calling lock() at the same time, because a scoped_lock object (as currently specified) is not thread safe (whereas a mutex is, by its very nature.)
Ugh, it would seem you are right Peter! Again, I quote the docs: "sharing a lock object between threads results in undefined behavior". Phooey!
class counter { public: counter() : count(0) { } void lock() { // nothing, methods act as self monitors } int increment() { boost::mutex::scoped_lock guard(this->mutex); return ++count; } void unlock { // nothing, methods act as self monitors } // ..Nothing to do here.. // ~counter() { // }
private: boost::mutex mutex; int count; };
This is also not quite equivalent to the original. In it, a lock() op1() op2() unlock() is a transaction; no other thread can inject its own op3 between op1 and op2.
Exactly - this is why I said "likewise" earlier, d-oh!
The closest you can get to the original, while somewhat respecting the requirement for it to be callable from outside C++, is:
scoped_lock * lock() { return new scoped_lock( mutex ); }
void unlock( scoped_lock * lock ) { delete lock; }
Although this respects the requirement that the code be callable from outside C++, it completely ignores the requirement that the COM interface (i.e. method prototype) should not change :-( Anyway, the last suggestion (changing the COM interface and returning a pointer to the scoped_lock) is probably the best I can do for now - I have indeed already considered this. The practitioner in me says it should be fine for my purposes. The theorist in me says I should keep moaning and groaning until someone truly feels my pain. soap_box->lock(); I've been making a stink largely because (IMHO) the decision to NOT expose functionality as fundamental as mutex.lock() and mutex.unlock() seems ridiculous! The boost library and accompanying docs should absolutely encourage the use of scoped_locks - I agree 100%. But it certainly shouldn't *disallow* me from using mutexes in the traditional way - to me this is a shortcoming. Even if there is some kind of overly complicated way (perhaps by deriving from mutex and calling some protected lock/unlock methods) I still think lock/unlock functionality should be exposed by mutex objects. Did you ever hear of the expression "you've polished the brass right off of the hinges"? This honestly seems like arrogance on the boost development team's part - why do they know how to use mutexes so much better than the rest of us? What am I, chopped liver over here? It is belittling! I'm not a child, whaaaaa!!!! ;-) There is little sense in going to such extreme lengths to protect developers from themselves - after all they are the ones writing the programs! Believe me, I would love to live to see the day that I simply install the Boost libraries and BINGO by some stroke of genius the program I intended to write is already done. I have a feeling it will be some time before this happens, until then my gun should shoot bullets wherever I point it, and I should be allowed to point it wherever I want (not where the boost developers THINK it should be pointed, but where I KNOW it should be pointed). As they say, "guns don't kill people, people kill people", lol. soap_box->unlock(); Just my 2 cents, C. Michailidis