C++ 并发消息队列
在网上找到了一份POSIX线程显示的并发消息队列示例代码:
http://codereview.stackexchange.com/questions/41604/thread-safe-concurrent-fifo-queue-in-c
上面的示例代码其实是有问题的,他只能对并发Push或者并发Pop进行上锁,二并不能保证同时Push和Pop是线程安全的,所以在锁队列时只能使用一个锁。同时该代码并不支持Windows,所以按照这篇文档的思路想使用标准模板库(STL)实现一份平台无关的代码,具体实现如下所示。
#include <queue>
#include <mutex>
#include <thread>
#include <chrono>
#include <memory>
#include <condition_variable> typedef struct task_tag
{
int data;
task_tag( int i ) : data(i) { }
} Task, *PTask; class MessageQueue
{
public:
MessageQueue(){}
~MessageQueue()
{
if ( !m_queue.empty() )
{
PTask pRtn = m_queue.front();
delete pRtn;
} } void PushTask( PTask pTask )
{
std::unique_lock<std::mutex> lock( m_queueMutex );
m_queue.push( pTask );
m_cond.notify_one();
} PTask PopTask()
{
PTask pRtn = NULL;
std::unique_lock<std::mutex> lock( m_queueMutex );
while ( m_queue.empty() )
{
m_cond.wait_for( lock, std::chrono::seconds() );
} if ( !m_queue.empty() )
{
pRtn = m_queue.front();
if ( pRtn->data != )
m_queue.pop();
} return pRtn;
} private:
std::mutex m_queueMutex;
std::condition_variable m_cond;
std::queue<PTask> m_queue;
}; void thread_fun( MessageQueue *arguments )
{
while ( true )
{
PTask data = arguments->PopTask(); if (data != NULL)
{
printf( "Thread is: %d\n", std::this_thread::get_id() );
printf(" %d\n", data->data );
if ( == data->data ) //Thread end.
break;
else
delete data;
}
} return;
} int main( int argc, char *argv[] )
{
MessageQueue cq; #define THREAD_NUM 3
std::thread threads[THREAD_NUM]; for ( int i=; i<THREAD_NUM; ++i )
threads[i] = std::thread( thread_fun, &cq ); int i = ;
while( i > )
{
Task *pTask = new Task( --i );
cq.PushTask( pTask );
} for ( int i=; i<THREAD_NUM; ++i)
threads[i].join(); //system( "pause" );
return ;
}
在示例代码中,我们使主线程向公共队列cq中Push任务,而其他的线程则负责取出任务并打印任务,由于std::cout并不支持并发线程安全,所以在打印任务时使用printf。主线程new出的任务,在其他线程中使用并销毁,当主线程发送data为0的任务时,则规定任务发送完毕,而其他的线程获取到data为0的任务后退出线程,data为0的任务则有消息队列负责销毁。整个消息队列使用标准模板库实现,现实跨平台。
在最初设计std::queue<PTask>的时候,想使用std::queue<std::shared_ptr<Task>>来管理主线程new出来的任务,这样智能指针则负责处理任务的销毁工作,但是在多线程并发的时候程序莫名的崩溃,仔细调试了半天,还是没有找到问题,最终我怀疑智能指针在多线程中是不是有问题呢?所以不得不放弃最初的设计。