Boost.Thread 的类似 CEvent 的行为

Posted

技术标签:

【中文标题】Boost.Thread 的类似 CEvent 的行为【英文标题】:CEvent-like behaviour with Boost.Thread 【发布时间】:2009-08-30 14:42:03 【问题描述】:

文字问题:

对于我的应用程序,我有一个从串行端口读取的类。它使用 Windows 原语进行 COM 端口处理,并有一个用于异步读取的线程。我正在尝试使用 Boost.Asio 和 Boost.Thread 等 Boost 库将其从 Windows 原语转换。

在 Windows 端口中,我的 IO 线程有几个 MFC CEvent 变量,每个变量代表一条消息:读取请求、写入请求、读取完成、写入完成、IO 取消。使用 WaitForMultipleObjects 等待这些。

我遇到的问题是 Boost.Thread 似乎既没有 CEvent 也没有 WaitForMultipleObjects 的类似物。我最接近的方法是丢弃这些并用一组布尔值替换事件,然后使用 condition_variable,只要布尔值发生变化,就会调用它的 notify_all() 函数。

然而,boost::condition_variable 与 CEvent 有一个关键的不同:如果 CEvent 在未被等待的情况下发出信号,那么下一次等待它会立即成功。使用 boost::condition_variable,如果没有等待,任何通知函数都会被忽略。

这意味着在检查标志和等待可能丢失通知的 condition_variable 之间总是存在间隙。这会导致线程挂起。

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

代码中的问题:

// 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】:

正如您所说,要类似于 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-semaphores,顺便说一句)的原因是这些原语很容易搞砸。如果您不打算将您的应用程序移植到另一个平台,那么将您的应用程序调整为这种不同的风格可能并不值得。

【讨论】:

以上是关于Boost.Thread 的类似 CEvent 的行为的主要内容,如果未能解决你的问题,请参考以下文章

终止正在运行的 boost 线程

Boost Thread int 参数到成员函数不起作用?

Boost.Thread 链接 - boost_thread 与 boost_thread-mt

Boost.Thread 还是只是::thread?

boost::thread & 成员函数

如何将参数传递给 boost::thread?