具有多个线程的安全消息队列

时间:2011-10-16 01:19:32

标签: c++ multithreading

这是我的本质所在:

我有线程A定期检查消息并处理它们。

线程B和C需要向A发送消息。

当A处理消息并因此访问队列时,B和C或B或C尝试向A发送消息时出现问题。

这个问题通常如何解决?

谢谢

2 个答案:

答案 0 :(得分:4)

这通常使用mutexes或其他多线程保护机制来解决。

如果您正在使用Windows,MFC会为此问题提供CMutex class

如果您正在使用posix系统,posix api会提供pthread_mutex_lock, pthread_mutex_unlock, and pthread_mutex_trylock functions

一些基本的伪代码可以方便地展示它们在你的情况下的使用:

pthread_mutex_t mutex; *or* CMutex mutex;
Q queue;  // <-- both mutex and queue are global state, whether they are
          //     global variables, or passed in as parameters, they must
          //     be the shared by all threads.

int threadA(/* params */){
    while( threadAStillRunning ){
        // perform some non-critical actions ...
        pthread_mutex_lock(mutex) *or* mutex.Lock()
        // perform critical actions ...
        msg = queue.receiveMessage()
        pthread_mutex_unlock(mutex) *or* mutex.Unlock()
        // perform more non-critical actions
    }
}

int threadBorC(/* params */){
    while( theadBorCStillRunning ){
        // perform some non-critical actions ...
        pthread_mutex_lock(mutex) *or* mutex.Lock()
        // perform critical actions ...
        queue.sendMessage(a_msg)
        pthread_mutex_unlock(mutex) *or* mutex.Unlock()
    }
}

对于所有三个线程,它们在队列中执行的能力取决于它们获取互斥锁的能力 - 它们将简单地阻塞并等待直到获取互斥锁。这可以防止因使用该资源而产生的冲突。

答案 1 :(得分:0)

如果您不在Windows上或者在C ++中实现跨平台的东西,请尝试使用ACE库中的Queue。

ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue;

作为ACE库样本的样本,您可以使用 将消息放入队列:

  ACE_NEW_RETURN (mb,
              ACE_Message_Block (rb.size (),
              ACE_Message_Block::MB_DATA,
              0,
              buffer),
              0);
  mb->msg_priority (ACE_Utils::truncate_cast<unsigned long> (rb.size ()));
  mb->wr_ptr (rb.size ());

  ACE_DEBUG ((LM_DEBUG,
          "enqueueing message of size %d\n",
          mb->msg_priority ()));

 // Enqueue in priority order.
 if (msg_queue->enqueue_prio (mb) == -1)
ACE_ERROR ((LM_ERROR, "(%t) %p\n", "put_next"));

从队列中获取:

 ACE_Message_Block *mb = 0;

 msg_queue->dequeue_head (mb) == -1;
 int length = ACE_Utils::truncate_cast<int> (mb->length ());

 if (length > 0)
   ACE_OS::puts (mb->rd_ptr ());

  // Free up the buffer memory and the Message_Block.
  ACE_Allocator::instance ()->free (mb->rd_ptr ());
  mb->release ();

优点是您可以非常轻松地更改同步原语,而无需编写太多代码。