开发者

What is unsafe in this extreme simple thread Monitor implementation?

I am new in thread syncronization. I was reading many implementations of conditional variables, like boost::threads and pthread for win32. I just implemented this quite simple monitor with wait/notify/noifyall, and i guess that there are many hidden problems with it, that I would like to discover from more experienced people. Any suggestion?

class ConditionVar
{

public :
    ConditionVar () : semaphore ( INVALID_HANDLE_VALUE ) , total_waiters (0)
    {
        semaphore = ::CreateSemaphoreA ( NULL , 0 /* initial count */ , LONG_MAX /* max count */ , NULL );
    }

    ~ConditionVar ()
    {
        ::CloseHandle ( semaphore ) ;       
    }


public :
    template <class P>
    void Wait ( P pred )
    {
        while ( !pred() ) Wait();
    }

public :

    void Wait ( void )
    {
        INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1开发者_运维问答 );
        ::WaitForSingleObject ( semaphore , INFINITE );
    }

    //! it will notify one waiter
    void Notify ( void )
    {
        if ( INTERLOCKED_READ_ACQUIRE(&total_waiters) )
        {
            Wake (1);
        }
    }

    void NotifyAll (void )
    {
        if ( INTERLOCKED_READ_ACQUIRE(&total_waiters) )
        {
            std::cout << "notifying " << total_waiters ;
            Wake ( total_waiters );
        }
    }

protected :
    void Wake ( int count )
    {
        INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count );
        ::ReleaseSemaphore ( semaphore , count , NULL );
    }

private :
    HANDLE semaphore;
    long    total_waiters;
};


I think bad things will happen if you copy your instance since both copies will use the same sempahore. This isn't necessarily a bad thing, but it might confuse people if the semantics aren't entirely clear.

You can easily fix this with a similar approach to what boost::noncopyable uses (or use boost).


I prefer Boost's implementation of wait(), because it takes an RAII lock object to make sure access to the shared condition state is synchronized. RAII makes it easier to write exception-safe code.

I have annotated the sample code found here:

boost::condition_variable cond;
boost::mutex mut;
bool data_ready;

void process_data();

void wait_for_data_to_process()
{
    boost::unique_lock<boost::mutex> lock(mut);  // Mutex acquired here (RAII).
    while(!data_ready) // Access to data_ready is sync'ed via mutex 'mut'
    {
        // While we are blocking, the mutex is released so
        // that another thread may acquire it to modify data_ready.
        cond.wait(lock);

        // Mutex is acquired again upon exiting cond.wait(lock)
    }
    process_data();

    // Mutex is released when lock goes out of scope.
}


if your using WinAPI functions, its probably better to use InterlockedIncrement(...) and InterlockedDecrement(...) instead of INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1 ); and INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count ); respectively.


(self answer)

i found a big mistake.

CondVars have an external lock... and this hasnt.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜