代码之家  ›  专栏  ›  技术社区  ›  Kaz Dragon

带有boost.thread的类cevent行为

  •  3
  • Kaz Dragon  · 技术社区  · 15 年前

    文字问题:

    对于我的应用程序,我有一个从串行端口读取数据的类。它使用windows原语处理com端口,并有一个线程用于异步读取。我正试图使用boost.asio和boost.thread等boost库将其从windows原语中转换出来。

    在windows端口中,我的io线程有几个mfc cevent变量,每个变量代表一条消息:read requested、write requested、read completed、write completed、io cancelled。这些都是用等待的东西等着的。

    我遇到的问题是boost.thread似乎既不支持cevent也不支持waitformultipleobjects。我最接近的方法是放弃这些并用一组布尔值替换事件,然后使用一个condition_变量,每当布尔值更改时,都会调用它的notify_all()函数。

    然而,boost::condition_变量在一个关键方面与cevent不同:如果一个cevent在未被等待时被发出信号,那么下一次对它的等待将立即成功。对于boost::condition_变量,如果任何notify函数没有等待,它都将被忽略。

    这意味着在检查标志和等待通知可能丢失的条件变量之间始终存在间隙。这会导致线程挂起。

    有人知道这个问题的解决办法吗?

    代码问题:

    // Old IO Thread
    CEvent msg_cancel;
    CEvent msg_read_req;
    CEvent msg_write_req;
    CEvent msg_read_comp;
    CEvent msg_write_comp;
    
    CEvent events[] = { 
        msg_cancel, 
        msg_read_req, 
        msg_write_req,
        msg_read_comp,
        msg_write_comp
    };
    
    bool cancel = false;
    
    while (!cancel)
    {
        switch(WaitForMultipleObjects(5, events, false, INFINITE))
        {
            case WAIT_OBJECT_0 :
                // msg_cancel
                cancel = true;
                break;
    
            ...
         }
    }
    

    如何在boost.thread中模拟它?

    1 回复  |  直到 15 年前
        1
  •  3
  •   gimpf    15 年前

    正如您所说,要类似于windows风格的事件,您需要一个条件变量和一个布尔标志。当然,如果满足您的需要,您可以将多个布尔标志合并为一个。

    但是,您提到的问题(条件变量永远不会得到 active 表示等待将立即返回)通常是这样解决的:

    condition-variable
    mutex
    
    main-thread:
      lock(mutex) { start condition-signaling-thread }
      while(some predicate) {
        condition-variable.wait(mutex)
        do-stuff
      }
    
    condition-signaling-thread:
      loop:      
        lock(mutex) {
          do-whatever
        }
        condition-variable.notify();
    

    通过让第二个线程等待互斥锁被将处理该条件的线程解锁,您可以确保每个条件都得到处理。(注意:在Java中,NoTIFY()方法必须在锁内调用,这取决于实现细节,如果在C++中完成,可能会导致更坏的性能,但确保程序员至少曾经想过如何同步条件与接收方的开机)。

    boost.thread不提供windows风格的事件(和posix信号量,顺便说一句)的原因是这些原语很容易出错。如果您不打算将应用程序移植到另一个平台,那么使应用程序适应这种不同的样式可能不值得。