2012-02-20 118 views
2

如果我在一個boost::unique_future設置set_wait_callback,是它保證只運行一次?boost :: future - 是否保證wait_callback只能被調用一次?

我是有點懷疑的源代碼看時,因爲我發現了以下內容:

struct relocker 
{ 
    boost::unique_lock<boost::mutex>& lock; 

    relocker(boost::unique_lock<boost::mutex>& lock_): 
     lock(lock_) 
    { 
     lock.unlock(); 
    } 
    ~relocker() 
    { 
     lock.lock(); 
    } 
private: 
    relocker& operator=(relocker const&); 
}; 

void do_callback(boost::unique_lock<boost::mutex>& lock) 
{ 
    if(callback && !done) 
    { 
     boost::function<void()> local_callback=callback; 
     relocker relock(lock); // unlock mutex? 
     local_callback(); 
    } 
}  

void wait(bool rethrow=true) 
{ 
    boost::unique_lock<boost::mutex> lock(mutex); 
    do_callback(lock); 
    while(!done) 
    { 
     waiters.wait(lock); 
    } 
    if(rethrow && exception) 
    { 
     boost::rethrow_exception(exception); 
    } 
} 

do_callback而調用回調函數,它從我的理解可能會導致互斥量實際上是解鎖如果多個線程調用wait函數,該回調將被多次調用?

可以在回調被調用多次?它是否由設計?或者我錯過了什麼?

我有點驚訝的原因是,在C++ 11標準async(std::launch::deferred, ...)(到set_wait_callback是表弟),似乎有一個調用的保證:

§30.6.8

在功能完成之前,共享狀態還沒有準備好。 第一呼叫到 異步返回對象參照該共享狀態應調用 在調用等待功能線程延遲功能在非定時等待功能(30.6.4)。

回答

2

我覺得你的懷疑成立。該代碼看起來應該像

void do_callback(boost::unique_lock<boost::mutex>& lock) 
{ 
    if(callback && !done) 
    { 
     boost::function<void()> local_callback=callback; 
     callback=boost::function<void()>; 
     relocker relock(lock); // unlock mutex? 
     local_callback(); 
    } 
}  

甚至

void do_callback(boost::unique_lock<boost::mutex>& lock) 
{ 
    if(callback && !done) 
    { 
     boost::function<void()> local_callback=boos::move(callback); 
     relocker relock(lock); // unlock mutex? 
     local_callback(); 
    } 
}  

一旦來自Boost.Function將支持移動語義。

這還沒有一些問題作爲另一個線程可能set_wait_callback打電話,所以回調中可以重新分配和兩個回調可能被調用。似乎需要額外的狀態來說明回調是否已經完成。

void do_callback(boost::unique_lock<boost::mutex>& lock) 
{ 
    if(callback && ! callback_done && !done) 
    { 
     boost::function<void()> local_callback=callback; 
     callback_done=true; 
     relocker relock(lock); // unlock mutex? 
     local_callback(); 
    } 
}  

順便說一句,set_wait_callback不是線程安全的。

template<typename F,typename U> 
    void set_wait_callback(F f,U* u) 
    { 
     callback=boost::bind(f,boost::ref(*u)); 
    } 

,必須保護

template<typename F,typename U> 
    void set_wait_callback(F f,U* u) 
    { 
     boost::lock_guard<boost::mutex> lock(mutex); 
     callback=boost::bind(f,boost::ref(*u)); 
    } 

請,你可以創建一個Trac的門票,以提高線程所以這個問題是不是失去了什麼?

+0

https://svn.boost.org/trac/boost/ticket/7798 – ronag 2012-12-15 11:54:02

+0

的問題是複雜得多,它似乎乍一看。從文檔看來,每次調用wait函數時都應該調用回調函數。 「效果: 存儲與*這是一個等待回調這將替換所有現有的等待回調店旁邊那個結果相關聯的異步結果f副本如果一個線程隨後調用在未來或升壓的等待功能之一。 :: shared_future與此結果關聯,並且結果尚未準備好,則應調用f(* this)。「 – 2012-12-15 14:22:45

相關問題