我是线程同步的新手。我正在阅读许多条件变量的实现,比如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;
};
答案 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有一个外部锁......这个没有。