2009-11-04 89 views
22

我試圖將一些Windows代碼移植到Linux,理想情況下通過獨立於平臺的庫(例如boost),但是我不確定如何移植此位事件代碼。跨平臺等效於Windows事件

代碼位包含兩個線程(讓我們稱它們爲A和B)。 A想要做一些只有B才能做的事情,所以它會發送一條消息,然後等待B完成它。在這個窗口看起來像:

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 :: condition_variable,但它似乎這意味着與一個互斥體結合使用,在這裏不是這種情況。

+0

我認爲你的特定於Windows的代碼在引擎蓋下使用了一個互斥鎖。它只是把這個摘要摘下來。 – rmeador 2009-11-04 23:26:57

+0

[pthread-like windows手動重置事件]的可能重複(http://stackoverflow.com/questions/178114/pthread-like-windows-manual-reset-event) – jww 2014-02-11 13:36:29

+0

[this question](http:// stackoverflow .com/questions/4692717/win32-reset-event-like-synchronization-class-with-boost-c)也有很好的信息 – Loomchild 2017-01-17 10:44:27

回答

10

我認爲一個良好的,跨平臺相當於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(); 
} 
+1

雖然這個互斥體真的需要嗎?我當然想知道這個事實,它意味着B可能會阻塞在酒吧(如果線程A的時間片在mtxWaitLock和cndSignal.wait之間過期)。 – 2009-11-04 22:47:06

+0

不需要第二個互斥鎖。你不需要持有互斥體來調用notify(有些情況下你需要)。 – 2009-11-04 23:25:43

+0

是的你說得對 - 我會修改代碼 – Alan 2009-11-04 23:54:34

2

可以使用升壓線程barrier

#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(); 
} 
+1

在某些情況下工作,但是障礙缺少一個超時值地方。 – 2009-11-04 22:41:11

-1

在POSIX兼容的系統,您可以使用POSIX IPC。它用於進程間/線程間消息傳遞。如果我沒有記錯,可以使用cygwin端口。

0

我做(或看到)都在不同時期下這樣的事情的:

使用互斥+條件變量。

使用一個管道,使foo創建管道並將其寫入結束條。當酒吧完成後,酒吧寫入管道。 (這甚至可以運行多進程)。

有一個布爾值(是的,這是一個壞主意。)

0

它看起來像你正在尋找信號插槽mechanizm FOO調查。你可以找到一個在:

boostQt

兩個跨平臺。

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); 
    } 
} 
+1

我不認爲升壓信號/插槽機制有任何類型的等待機制 – 2009-11-04 22:47:31

+0

但是對於信號/插槽,我沒有看到有什麼理由等待()? 如果準備好了,只需發佈​​消息,任何感興趣的客戶都會採取適當的行動。 簡單的觀察者設計模式。 – bua 2009-11-04 23:01:44

+0

@bua執行'waitForReadyRead'方法至少有一個等待的理由。在這種情況下,您必須等待數據,並且不應該阻止QT事件。 – baltazar 2012-01-13 13:41:31

14

所有這些問題的答案都太複雜的,來吧人們這並不難。

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語義(如果兩個線程調用它同時會發生什麼,會發生什麼,如果在同一個線程稱它兩次)。但是,解決方案看起來非常像這樣。

0

從Boost.Thread 1.47版本documentation

的類condition_variable和condition_variable_any提供 機制,一個線程等待通知從另一個線程 一個特定的條件已經成爲現實。

4

由於評論已關閉,我不得不發表我的評論到以前的帖子作爲答案。但實際上我沒有回答。

1)有與@Alan的解決的問題。 他提供的示例代碼運行良好。但它與Windows事件功能不同。當Windows Event對象是任意數量的後續調用WaitForSingleObject立即返回,顯示該對象處於信號狀態。但有了boost的mutex/condition解決方案,bar()必須通知需要它的每個foo()調用的條件。這使得「跨平臺」Windows事件功能的情況變得更加困難。 notify_all()也幫不上忙。

當然這是在@ deft_code的示例代碼通過使用布爾變量以某種方式解決的。 (雖然它受到本身的競爭條件的問題。試想,如果SetEvent(...)while(!evt->m_bool)evt->m_cond.wait(lock)從一個單獨的線程中調用之前死了。會發生死鎖。這可以然而,可以通過使用一些競爭條件的管理技術,使兩個報表解決while()wait()原子),但它有自己的缺點:

2)還有在利用升壓與@deft_code的代碼問題mutex/condition/bool組合:在Windows

事件對象可以是,命名爲它使它們能夠用於進程間同步。例如,過程A可以創建一個命名事件並將其設置爲:SetEvent(hFileIsReady)。隨後,被設置任何等待該事件處理號(從而調用WaitForSingleObject(hFileIsReady))將立即繼續正常執行,直到事件再次進程A內ResetEvent(hFileIsReady)復位。

但是組合mutex/condition/bool無法承擔這樣的功能。當然,我們可以使用boost named_conditionnamed_mutex。但是,等待之前我們必須檢查的布爾變量呢?

8

你可以使用一個承諾和未來,從升壓螺紋:

#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); 
} 
2

對於任何參與或移植工作的多線程的原生Windows的C/C++代碼的Linux/Mac上,we've authored an open source (MIT-licensed) library同時實現手動和自動重置pthread上的WIN32事件,包括完整的實現WaitForSingleObjectWaitForMultipleObjects,使它成爲我所知道的Linux/Mac上唯一的WFMO端口。

pevents is available on GitHub並已相當久經考驗的,是一些大牌的使用;還有一個漂浮在某個地方的大型活動。

使用pevents將使Windows移植代碼更容易,因爲底層範例在Windows和posix平臺之間顯着不同 - 儘管我鼓勵任何編寫多平臺代碼的人使用現有的跨平臺多線程庫,如boost第一個地方。

+0

謝謝!我一直在尋找適合年齡的便攜式WFMO解決方案。很遺憾C++標準沒有提供任何接近它的東西,AFAIK,boost也不是。我絕對有一些立即使用你的圖書館。 – 2017-09-29 14:45:51