C. Michailidis wrote:
do have models. What prevents you from using say, the boost::mutex::scoped_lock model? (Which has the lock/unlock calls.)
Perhaps my initial mailing was too general.
It was ;-)
I'll try to state my problem more specifically. The following url, http://www.boost.org/libs/thread/example/mutex.cpp , gives an example of how mutexes and scoped_locks are typically used. The counter class shows how an atomic counter is implemented. For completeness I'll copy and paste part of the example into my email, here's the class:
class counter { public: counter() : count(0) { }
int increment() { boost::mutex::scoped_lock scoped_lock(mutex); return ++count; }
private: boost::mutex mutex; int count; };
As I understand it, a thread calling the 'increment' method will be blocked until any other thread that has already called 'increment' has returned from the method call (more or less). When the scoped_lock object is instantiated its constructor locks the mutex until the scoped_lock goes out of scope (at which time the destructor of scoped_lock unlocks the mutex enabling other threads to reach the body of increment).
Your understanding is correct, as far as the above code goes.
This is all fine and dandy. My problem is that I have an existing COM component which is more similar to:
// please excuse the MSFT parlance class counter { public: counter() : count(0) { mutex=CreateMutex(NULL, false, NULL); } void lock() { WaitForSingleObject(mutex, INFINITE); } int increment() { return ++count; } void unlock { ReleaseMutex(mutex); } ~counter() { CloseHandle(mutex); }
private: unsigned long mutex; int count; };
When using the COM component the caller is required to call 'lock' before calling any other methods (in this case 'increment'), when you are finished using the component you must call 'unlock'.
So... here's my problem, how can I use Boost.Threads to create the same kind of functionality without changing my COM interfaces? Remember that this is just for illustration so my sample code may need changes before compiling ;-)
Answer.. Don't take the examples at their face value ;-) Concretely 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; }; But.. The asserts above should give you a hint of why this usage is *Not a Good Thing* (tm) normally. Of course there's nothing that prevents you from still going the safe route and doing this: 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; }; After all one would hope you are following reasonable encapsulation rules.
In any case, the actual component is more sophisticated than the simple example I gave, and could actually be called from a language other than C++ (e.g. Visual Basic). AFAIK boost mutexes must be locked using scoped_locks and it would seem that they aren't appropriate for my situation. I can certainly appreciate the benefits of scoped_locks (esp. in a homogeneous environment where all code is written in C++). It just seems silly to force the user to use ONLY scoped_locks when in some situations the additional requirements they have make them unusable. Sure, most of the time the mutex should be unlocked at the end of the block... however when the critical section is composed of code written in more than one language or in a more dynamic algorithm it may easier to unlock it elsewhere, no?
No real argument from me, and probably others, it's just a different point of view. Boost is mainly about standard C++. If we started designing with every possible outside use of code nothing would ever get done.
It's my opinion that a great toolkit not only provides robust and sophisticated facilities but *ALSO* gives the developer enough 'rope to hang themselves'. After all, isn't the freedom to shoot yourself in the foot one of the major advantages of writing code in C/C++?
With enough creativity, you can shoot yourself in the foot an infinite number of ways. But C++ is also about reducing the number of ways you can do that so that you only shoot when you really mean to shoot. After all you really want that shot to go between your toes, not through your bones. [...]
Any suggestions?
Think differently.
Any boost developers reading this?
Usually.
Anyone feel my pain?
We wouldn't be creating Boost libraries if we didn't.
Am I just being blindly stubborn?
Beauty is in the eye of the beholder. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - Grafik/jabber.org