这个极端简单的线程Monitor实现中有什么不安全的?

时间:2010-01-27 16:27:52

标签: c++ multithreading monitor

我是线程同步的新手。我正在阅读许多条件变量的实现,比如boost :: threads和win32的pthread。我刚用wait / notify / noifyall实现了这个非常简单的监视器,我猜它有很多隐藏的问题,我想从更有经验的人那里发现。有什么建议吗?

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

4 个答案:

答案 0 :(得分:2)

我认为如果复制你的实例会发生不好的事情,因为两个副本都会使用相同的sempahore。这不一定是坏事,但如果语义不完全清楚,它可能会让人感到困惑。

您可以使用与boost::noncopyable使用(或使用提升)类似的方法轻松解决此问题。

答案 1 :(得分:1)

我更喜欢Boost的wait()实现,因为它需要一个RAII锁定对象来确保同步对共享条件状态的访问。 RAII可以更轻松地编写异常安全的代码。

我已注释找到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.
}

答案 2 :(得分:0)

如果您使用WinAPI功能,最好分别使用InterlockedIncrement(...)InterlockedDecrement(...)代替INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1 );INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count );

答案 3 :(得分:0)

(自我回答)

我发现了一个大错误。

CondVars有一个外部锁......这个没有。