2

我是线程同步的新手。我正在阅读许多条件变量的实现,例如 win32 的 boost::threads 和 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

4 回答 4

2

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

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

于 2010-01-27T17:14:48.717 回答
1

我更喜欢 Boost 的实现wait(),因为它需要一个 RAII 锁定对象来确保对共享条件状态的访问是同步的。RAII 使编写异常安全代码变得更加容易。

我已经注释了这里找到的示例代码:

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.
}
于 2010-01-27T18:36:59.830 回答
0

(自我回答)

我发现了一个大错误。

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

于 2010-01-27T19:13:22.507 回答
0

如果您使用 WinAPI 函数,最好分别使用InterlockedIncrement(...)andInterlockedDecrement(...)而不是INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1 );and INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count );

于 2010-01-27T17:03:00.823 回答