跨平台等同于Windows事件

我试图移植一些Windows代码到Linux,理想情况下通过独立于平台的库(例如boost),但是我不知道如何移植这一点的事件代码。

代码位包含两个线程(让我们称之为A和B)。 A想要做的事情只有B可以,所以它发送一个消息,然后等待B说完成。 在Windows中,这看起来像这样:

void foo();//thread a calls this void bar(HANDLE evt); void foo() { HANDLE evt = CreateEvent(0,FALSE,FALSE,0); bCall(boost::bind(&bar, evt)); WaitForSingleObject(evt,INFINITE); CloseHandle(evt); } void bar(HANDLE evt) { doSomething(); SetEvent(evt); } 

我查看了boost :: thread库,但似乎没有任何这样做,closures我可以看到的是boost :: condition_variable,但它似乎意味着与一个互斥的结合,这是不是这里。

我认为一个和win32事件相当的跨平台是boost :: condition ,所以你的代码看起来像这样:

 void foo() { boost::mutex mtxWait; boost::condition cndSignal; bCall(boost::bind(&bar, mtxWait, cndSignal)); boost::mutex::scoped_lock mtxWaitLock(mtxWait); cndSignal.wait(mtxWait); // you could also use cndSignal.timed_wait() here } void bar(boost::mutex& mtxWait, boost::condition& cndSignal) { doSomething(); cndSignal.notify_one(); } 

所有这些答案太复杂了,来吧人不难。

 namespace porting { class Event; typedef Event* Event_handle; static const unsigned k_INFINITE = 0xFFFFFFFF; class Event { friend Event_handle CreateEvent( void ); friend void CloseHandle( Event_handle evt ); friend void SetEvent( Event_handle evt ); friend void WaitForSingleObject( Event_handle evt, unsigned timeout ); Event( void ) : m_bool(false) { } bool m_bool; boost::mutex m_mutex; boost::condition m_condition; }; Event_handle CreateEvent( void ) { return new Event; } void CloseHandle( Event_handle evt ) { delete evt; } void SetEvent( Event_handle evt ) { evt->m_bool = true; evt->m_cond.notify_all(); } void WaitForSingleObject( Event_handle evt, unsigned timeout ) { boost::scoped_lock lock( evt->m_mutex ); if( timeout == k_INFINITE ) { while( !evt->m_bool ) { evt->m_cond.wait( lock ); } } else { //slightly more complex code for timeouts } } }// porting void foo() { porting::Event_handle evt = porting::CreateEvent(); bCall( boost::bind(&bar, evt ) ); porting::WaitForSingleObject( evt, porting::k_INFINITE ); porting::CloseHandle(evt); } void bar( porting::Event_handle evt ) { doSomething(); porting::SetEvent(evt); } 

因为我不熟悉WaitForSingleObject的语义(如果两个线程同时调用它会发生什么情况,如果同一个线程调用它两次会发生什么情况),可能WaitForSingleObject要做更多的工作来完成这个工作。 但是,解决方案看起来非常像这样。

您可以使用承诺和未来,从提升线程:

 #include <boost\thread.hpp> boost::promise<bool> prom; void foo() { auto future = prom.get_future(); auto result = future.wait_for(boost::chrono::milliseconds(1000)); // we get here if (a) 1 second passes or (b) bar sets the promise value if (result==boost::future_status::ready) { /* bar set the promise value */ } if (result==boost::future_status::timeout) { /* 1 second passed without bar setting promise value */ } } void bar() { prom.set_value(true); } 

由于意见对我来说是封闭的,所以我不得不把我的意见发表到以前的帖子上作为答案。 但实际上我不回答。

1) @Alan的解决方案存在问题。 他提供的示例代码运行良好。 但它与Windows事件功能不同。 当设置一个Windows事件对象时, 任何数量的WaitForSingleObject 后续调用立即返回,表明该对象处于信号状态。 但是用boost的mutex / condition解决方案, bar()必须通知每个需要它的foo()调用的条件。 这使得“跨平台”Windows事件功能的情况变得更加困难。 notify_all()也帮不上忙。

当然,这是通过使用布尔变量在@deft_code的示例代码中解决的。 (虽然它受到竞争条件问题的困扰,但考虑如果SetEvent(...)while(!evt->m_bool)evt->m_cond.wait(lock)从另一个线程中evt->m_cond.wait(lock)死锁将会然而这可以通过使用一些竞争条件管理技术来解决while()wait()原子)。但是它有它自己的缺点:

2)在使用boost mutex / condition / bool组合时,@deft_code的代码也有问题:

可以命名 Windows中的事件对象,使它们能够用于进程间同步。 例如,进程A可以创建一个命名事件并将其设置为: SetEvent(hFileIsReady) 之后,等待这个事件被设置的任何数量的进程 (由此调用WaitForSingleObject(hFileIsReady) )将立即继续它们的正常执行,直到通过ResetEvent(hFileIsReady)在进程A内再次重置事件。

但组合mutex / condition / bool不能提供这样的功能。 当然,我们可以使用boost named_conditionnamed_mutex 但是,等待之前我们必须检查的布尔变量呢?

你可以使用boost线程屏障

 #include <boost/thread/thread.hpp> #include <boost/thread/barrier.hpp> #include <iostream> void foo(boost::barrier* b) { std::cout << "foo done" << std::endl; b->wait(); } int main() { std::cout << "start foo" << std::endl; boost::barrier b(2); boost::thread t(&foo, &b); b.wait(); std::cout << "after foo done" << std::endl; t.join(); } 

对于任何参与或正在将多线程本机Windows C / C ++代码移植到Linux / Mac的人员, 我们已经编写了一个开源(MIT许可)库 ,在pthread上实现手动和自动重置WIN32事件,包括WaitForSingleObjectWaitForMultipleObjects一个完整实现,使之成为我所知道的Linux / Mac上唯一的WFMO端口。

GitHub上提供了一些游戏,并且已经过相当的战斗测试,并被一些大牌使用。 还有一个漂浮在附近某处的大型活化剂。

使用pevents将使得从Windows移植代码变得更容易,因为底层范例在Windows和posix平台之间显着不同 – 尽管我鼓励任何人编写多平台代码来使用现有的跨平台多线程库,比如boost。

我已经在不同的时间完成了(或者看过)以下的所有事情:

使用互斥+条件变量。

使用一个管道,让富创建管道,并通过它的写入结束。 当酒吧完成后,酒吧写入管道。 (这甚至可以运行多进程)。

有foo民意调查布尔(是的,这是一个坏主意。)

它看起来像你正在寻找信号槽mechanizm。 你可以找到一个:

提升和Qt

两个跨平台。

Qt例子:

  #include <QObject> class Counter : public QObject { Q_OBJECT public: Counter() { m_value = 0; } int value() const { return m_value; } public slots: void setValue(int value); signals: void valueChanged(int newValue); private: int m_value; }; Counter a, b; QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int))); a.setValue(12); // a.value() == 12, b.value() == 12 b.setValue(48); // a.value() == 12, b.value() == 48 void Counter::setValue(int value) { if (value != m_value) { m_value = value; emit valueChanged(value); } } 

从Boost.Thread版本1.47 文档 :

类condition_variable和condition_variable_any提供了一种机制,让一个线程等待来自另一个线程的特定条件成立的通知。

在Posix兼容系统下,您可以使用Posix IPC。 它用于进程间/线程间消息传递。 如果我没有记错,可以使用cygwin端口。