Boost logo

Boost Users :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2005-04-10 02:45:44


Rene Rivera wrote:
> C. Michailidis wrote:
>> // 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?

See below, but it's not pretty.

[...]

>> 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;
> };

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.)

[...]

> 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.

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;
}

In a C++ only program, lock() should return an auto_ptr<scoped_lock> and
unlock() can be omitted.

Another option is to stick the scoped_lock* into a thread_specific_ptr.

private:

    thread_specific_ptr<scoped_lock> lock_;
    mutex mutex_;

public:

    void lock()
    {
        lock_.reset( new scoped_lock(mutex_) );
    }

    void unlock()
    {
        lock_.reset();
    }


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