我有一个类Queue
,我尝试使线程安全。它有以下三个成员变量:
std::queue<T> m_queue;
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
和推送和弹出实现为:
template<class T> void Queue<T>::push(T value)
{
pthread_mutex_lock( &m_mutex );
m_queue.push(value);
if( !m_queue.empty() )
{
pthread_cond_signal( &m_condition );
}
pthread_mutex_unlock( &m_mutex );
}
template<class T> bool Queue<T>::pop(T& value, bool block)
{
bool rtn = false;
pthread_mutex_lock( &m_mutex );
if( block )
{
while( m_queue.empty() )
{
pthread_cond_wait( &m_condition, &m_mutex );
}
}
if( !m_queue.empty() )
{
value = m_queue.front();
m_queue.pop();
rtn = true;
}
pthread_mutex_unlock( &m_mutex );
return rtn;
}
不幸的是,偶尔出现的问题可能是此代码的错误。也就是说,有两个线程,有时线程1永远不会来自push()
,有时线程2永远不会来自pop()
(block
参数是true
)虽然队列不是空的。
我知道还有其他可用的实现,但我想尝试修复此代码,如果需要的话。有人看到任何问题吗?
构造函数具有适当的初始化:
Queue()
{
pthread_mutex_init( &m_mutex, NULL );
pthread_cond_init( &m_condition, NULL );
}
和析构函数,相应的'destroy'调用。
答案 0 :(得分:1)
如Paul Rubel所述,您需要首先初始化互斥锁。在这一点上,将互斥锁包装在一个可以为您处理初始化和最终化的类中可能是一个好主意。例如:
class mutex {
private:
mutex(const mutex &m);
mutex &operator=(const mutex &m);
// OR inherit from boost::noncopyable
public:
mutex() {
pthread_mutex_init(&mut_, nullptr);
}
~mutex() {
pthread_mutex_destroy(&mut_);
}
pthread_mutex_t get() const { return mut_; }
private:
pthread_mutex_t mut_;
};
值得注意的是Boost.Threading库,其中包含编写良好的同步类。
答案 1 :(得分:0)
您必须在使用之前初始化互斥锁:pthread_mutex_init
//somewhere before push/pop
pthread_mutex_init(&m_mutex)
答案 2 :(得分:0)
这与您的问题无关,但您可以修复推送功能:
template<class T> void Queue<T>::push(T value)
{
pthread_mutex_lock( &m_mutex );
if( m_queue.empty() )
{
m_queue.push(value);
pthread_cond_signal( &m_condition );
}
else
{
m_queue.push(value);
}
pthread_mutex_unlock( &m_mutex );
}
答案 3 :(得分:0)
我意识到测试ARM构建时出现了问题。解决方案是更新pthreads库。使用更新的pthreads,一切运行正常。