线程安全队列有问题吗? 我试图用C++中的p螺纹编写一个线程安全队列。我的程序93%的时间都能正常工作。另外7%的时间它会吐出垃圾,或者似乎睡着了。我想知道我的队列中是否存在某种缺陷,上下文切换会破坏它 // thread-safe queue // inspired by http://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks.aspx // only works with one producer and one consumer #include <pthread.h> #include <exception> template<class T> class tsqueue { private: volatile int m_ReadIndex, m_WriteIndex; volatile T *m_Data; volatile bool m_Done; const int m_Size; pthread_mutex_t m_ReadMutex, m_WriteMutex; pthread_cond_t m_ReadCond, m_WriteCond; public: tsqueue(const int &size); ~tsqueue(); void push(const T &elem); T pop(); void terminate(); bool isDone() const; }; template <class T> tsqueue<T>::tsqueue(const int &size) : m_ReadIndex(0), m_WriteIndex(0), m_Size(size), m_Done(false) { m_Data = new T[size]; pthread_mutex_init(&m_ReadMutex, NULL); pthread_mutex_init(&m_WriteMutex, NULL); pthread_cond_init(&m_WriteCond, NULL); pthread_cond_init(&m_WriteCond, NULL); } template <class T> tsqueue<T>::~tsqueue() { delete[] m_Data; pthread_mutex_destroy(&m_ReadMutex); pthread_mutex_destroy(&m_WriteMutex); pthread_cond_destroy(&m_ReadCond); pthread_cond_destroy(&m_WriteCond); } template <class T> void tsqueue<T>::push(const T &elem) { int next = (m_WriteIndex + 1) % m_Size; if(next == m_ReadIndex) { pthread_mutex_lock(&m_WriteMutex); pthread_cond_wait(&m_WriteCond, &m_WriteMutex); pthread_mutex_unlock(&m_WriteMutex); } m_Data[m_WriteIndex] = elem; m_WriteIndex = next; pthread_cond_signal(&m_ReadCond); } template <class T> T tsqueue<T>::pop() { if(m_ReadIndex == m_WriteIndex) { pthread_mutex_lock(&m_ReadMutex); pthread_cond_wait(&m_ReadCond, &m_ReadMutex); pthread_mutex_unlock(&m_ReadMutex); if(m_Done && m_ReadIndex == m_WriteIndex) throw "queue empty and terminated"; } int next = (m_ReadIndex +1) % m_Size; T elem = m_Data[m_ReadIndex]; m_ReadIndex = next; pthread_cond_signal(&m_WriteCond); return elem; } template <class T> void tsqueue<T>::terminate() { m_Done = true; pthread_cond_signal(&m_ReadCond); } template <class T> bool tsqueue<T>::isDone() const { return (m_Done && m_ReadIndex == m_WriteIndex); }

线程安全队列有问题吗? 我试图用C++中的p螺纹编写一个线程安全队列。我的程序93%的时间都能正常工作。另外7%的时间它会吐出垃圾,或者似乎睡着了。我想知道我的队列中是否存在某种缺陷,上下文切换会破坏它 // thread-safe queue // inspired by http://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks.aspx // only works with one producer and one consumer #include <pthread.h> #include <exception> template<class T> class tsqueue { private: volatile int m_ReadIndex, m_WriteIndex; volatile T *m_Data; volatile bool m_Done; const int m_Size; pthread_mutex_t m_ReadMutex, m_WriteMutex; pthread_cond_t m_ReadCond, m_WriteCond; public: tsqueue(const int &size); ~tsqueue(); void push(const T &elem); T pop(); void terminate(); bool isDone() const; }; template <class T> tsqueue<T>::tsqueue(const int &size) : m_ReadIndex(0), m_WriteIndex(0), m_Size(size), m_Done(false) { m_Data = new T[size]; pthread_mutex_init(&m_ReadMutex, NULL); pthread_mutex_init(&m_WriteMutex, NULL); pthread_cond_init(&m_WriteCond, NULL); pthread_cond_init(&m_WriteCond, NULL); } template <class T> tsqueue<T>::~tsqueue() { delete[] m_Data; pthread_mutex_destroy(&m_ReadMutex); pthread_mutex_destroy(&m_WriteMutex); pthread_cond_destroy(&m_ReadCond); pthread_cond_destroy(&m_WriteCond); } template <class T> void tsqueue<T>::push(const T &elem) { int next = (m_WriteIndex + 1) % m_Size; if(next == m_ReadIndex) { pthread_mutex_lock(&m_WriteMutex); pthread_cond_wait(&m_WriteCond, &m_WriteMutex); pthread_mutex_unlock(&m_WriteMutex); } m_Data[m_WriteIndex] = elem; m_WriteIndex = next; pthread_cond_signal(&m_ReadCond); } template <class T> T tsqueue<T>::pop() { if(m_ReadIndex == m_WriteIndex) { pthread_mutex_lock(&m_ReadMutex); pthread_cond_wait(&m_ReadCond, &m_ReadMutex); pthread_mutex_unlock(&m_ReadMutex); if(m_Done && m_ReadIndex == m_WriteIndex) throw "queue empty and terminated"; } int next = (m_ReadIndex +1) % m_Size; T elem = m_Data[m_ReadIndex]; m_ReadIndex = next; pthread_cond_signal(&m_WriteCond); return elem; } template <class T> void tsqueue<T>::terminate() { m_Done = true; pthread_cond_signal(&m_ReadCond); } template <class T> bool tsqueue<T>::isDone() const { return (m_Done && m_ReadIndex == m_WriteIndex); },c++,multithreading,concurrency,queue,pthreads,C++,Multithreading,Concurrency,Queue,Pthreads,如果有人认为这有问题,请说:)如果这是您的实际代码,一个问题是您正在初始化m_writesecond两次,而根本没有初始化m_ReadCond。是的,这里肯定有问题。对队列成员变量的所有访问都发生在互斥锁之外。事实上,我不完全确定互斥体在保护什么,因为它们只是等待条件变量 另外,您的读写器似乎总是在锁定步骤中运行,从不允许队列的大小超过一个元素。问题似乎在于,您有一个争用条件,线程2可以在线程1执行任何cin.get(c)之前运行。需要确保数据已初始化,并且当您获取信息时,如果未输入数据,则确保

如果有人认为这有问题,请说:)

如果这是您的实际代码,一个问题是您正在初始化
m_writesecond
两次,而根本没有初始化
m_ReadCond

是的,这里肯定有问题。对队列成员变量的所有访问都发生在互斥锁之外。事实上,我不完全确定互斥体在保护什么,因为它们只是等待条件变量


另外,您的读写器似乎总是在锁定步骤中运行,从不允许队列的大小超过一个元素。

问题似乎在于,您有一个争用条件,线程2可以在线程1执行任何cin.get(c)之前运行。需要确保数据已初始化,并且当您获取信息时,如果未输入数据,则确保您正在执行某些操作


也许这是因为我看不到代码的其余部分是如何完成的。

您应该将该类视为一个类。每个队列都应该有一个“监视器锁”(一个普通的互斥锁)。每当您输入读取或写入队列中任何字段的方法时,应在输入该互斥锁后立即锁定该互斥锁。这可以防止一次有多个线程与队列交互。您应该在等待某个条件之前以及离开某个方法时释放锁,以便其他线程可以进入。确保在等待条件完成后重新获取锁。

如果您需要性能良好的锁,我强烈建议您放弃R/W锁,只需使用一个非常简单的自旋锁。或者,如果你真的认为使用R/W锁可以获得你想要的性能,我会根据Joe Duffy的设计(单字R/W自旋锁)推出你自己的。

MSVC编译器?你是在多核机器上吗?你真的测量了精确的93%/7%的速率吗?哈哈,罗布——gcc。我认为是单核的,但我在学校的电脑上运行它,所以我不能完全确定。奥古斯托--运行了32次,失败了两次。非常接近:)我想我应该四舍五入到94%,我有互斥锁的唯一原因是pthread_cond_wait需要它们。因为我一次只有一个读写器,所以不应该同时读写变量(有互斥锁或没有互斥锁)。哦,我不确定你说的它们将在锁步中运行是什么意思。为什么会这样?只有当线程1和线程2以完全相同的速度运行并且在不同的CPU上时,才会发生这种情况吗?否则线程1可能会在调用线程2之前运行好几次。哦,哇,完全错过了。我很惊讶这东西没有爆炸。谢谢:)锁定整个队列似乎有点低效,不是吗?没有理由它不能同时读写,只要它不是对同一个元素。不过我很欣赏这个建议:)你需要保护整个共享状态。读卡器和写卡器都访问这两个索引,因此实际上需要锁定整个队列。对于两个线程,这不是什么大问题。如果你有很多读者和作者,那么就查找读者-作者问题,寻找一种更有效的方法。我认为你遗漏了一些东西。如果先调用
pop()
,那么
m_ReadIndex==m_WriteIndex
线程2将进入睡眠状态,直到发出信号。啊,谢谢。我来看看这个!我还是多线程新手。
// thread 1
while(cin.get(c)) {
    queue1.push(c);
}
queue1.terminate();


// thread 2
while(!queue1.isDone()) {
    try{ c = queue1.pop(); }
    catch(char const* str){break;}
    cout.put(c);
}