【问题标题】:How to structure code for waiting on two signal objects from unrelated classes?如何构造代码以等待来自不相关类的两个信号对象?
【发布时间】:2012-03-26 16:39:43
【问题描述】:

我有一个后台线程:

class Queue
{
public:
  Message* WaitForMessage(uint32_t uTimeOutMS);

private:
  SignalObject soMessage; // Signalled when a message is added to the queue
};

class MyThread : Thread
{
public:
  bool IsToStop() const { return soStop.IsSignalled(); }

  void ThreadFunction()
  {
     while (!IsToStop()) {
        Message* pMessage = queue1.GetMessage();
        if (pMessage != nullptr) ProcessMessage(pMessage);

        pMessage = queue2.GetMessage();
        if (pMessage != nullptr) ProcessMessage(pMessage);

        Sleep(100); etal // If I wait for 1 ms I hog the CPU, if I wait for 100 ms I waste time when the thread should be stopped
     };
  }

private:
  SignalObject soStop; // Signalled when the thread should stop

  Queue queue1;
  Queue queue2;
};

我想摆脱睡眠并同时等待信号对象(这应该在我等待信号对象时释放一些 CPU)。 我可以让它们成为 Queue 上的信号对象,然后做这样的事情:

while (true) {
  WaitForSignalObjectsForever(soStop, queue1.soMessage, queue2.soMessage); // Returns after any signal object is signalled
  if (IsToStop()) break;

  Message* pMessage = queue1.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);

  pMessage = queue2.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);
}

或者这个:

while (true) {
  soStop.WaitForSignalObjectsForever(queue1.soMessage, queue2.soMessage); // Returns after any signal object is signalled
  if (IsToStop()) break;

  Message* pMessage = queue1.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);

  pMessage = queue2.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);
}

或者这个:

while (WaitForSignalObjectsOrIsToStopForever(queue2.soMessage, queue1.soMessage)) { // Returns true if soStop is signalled, false if one of the other signal objects was signalled
  Message* pMessage = queue1.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);

  pMessage = queue2.GetMessage();
  if (pMessage != nullptr) ProcessMessage(pMessage);
}

我认为我更喜欢第一个版本,因为它更通用。不过,我仍然对将信号对象公开(或通过朋友访问保护)感到恶心。谁有更好的解决方案?

我也习惯称它们为信号对象,有没有更通用的名称?

【问题讨论】:

    标签: c++ multithreading message-queue


    【解决方案1】:

    最好的方法是接收者负责队列,因此它只需要等待一个队列上的消息,然后将引用传递给必须传递消息的任何人。更好的是隐藏消息发送,因此客户端线程只需调用一个函数,该函数就会发送一条消息。

    如果不可能,我会通过将信号(条件变量?)传递给构造函数来加入信号(条件变量?),以便发送者可以向线程发出信号,也可以向线程发出信号,以便向它发出信号以检查其队列。

    【讨论】:

      【解决方案2】:

      在你有 WaitForMultipleObjects 的窗口中,你可以写这样的东西(在伪代码中)

      while (!gotallmessages())
           WaitForMultipleObjects( {queue1.signal, queue2.signal} )
      

      另一种解决方案是创建多个线程来监控队列:

      void queuemonitor(master*m, Queue *q)
      {
           msg= q->GetMessage();
           m->notify();
      }
      

      并在主线程中执行以下操作:(使用来自 boost/thread.hpp 的条件 + 互斥锁)

      condition cond;
      mutex  mtx;
      
      void notify(int id)
      {
           scoped_lock l(mtx);
           notifycount++;
           cond.notify_one();
      }
      
      void masterthread()
      {
           scoped_lock l(mtx);
           while (notifycount<2)
               cond.wait(l);
      
           // ... this is what we waited for
      }
      

      【讨论】:

      • 我在考虑 WaitForMultipleObjects 但不幸的是我使用的是 Boost,它没有包装它,因为它不能移植到 pthreads,我想保持它的便携性。我认为另外两个线程对我来说是最好的选择,当任何一个线程发生问题时,它们可以向这个等待线程发出信号。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-06
      • 2019-02-07
      • 1970-01-01
      • 2017-06-28
      • 2013-05-10
      • 2014-08-04
      相关资源
      最近更新 更多