Boost logo

Boost Users :

From: Rene Rivera (grafik.list_at_[hidden])
Date: 2005-04-09 21:47:19


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

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net