2012-02-20 11 views
2

boost::unique_futureset_wait_callbackを設定した場合、1回だけ動作することが保証されますか?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にmutexが実際にロックが解除され

、複数のスレッドがwait関数を呼び出す場合、コールバックは複数回呼び出されますか?

コールバックを複数回呼び出すことはできますか?それは設計によるのですか?または私は何かを逃している?

私は少し驚いた理由は、(set_wait_callbackがいとこであるに)async(std::launch::deferred, ...) C++ 11標準では、単一の呼び出しの保証を持っているように見えるということです。

§30.6.8

共有状態は、機能が完了するまで準備されていません。 最初のコールウェイティング機能を呼び出したスレッドに遅延機能 を起動しなければならないこの共有状態を参照 非同期リターンオブジェクトの非時限待機機能(30.6.4)に

答えて

2

あなたの疑惑が設立されたと思います。 Boost.Functionは移動セマンティクスをサポートします一度コードが

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

のようになります。

これは、別のスレッドがset_wait_callbackを呼び出す可能性があるため、まだいくつかの問題があるため、コールバックを再割り当てして2つのコールバックを呼び出すことができます。コールバックがすでに完了しているかどうかを示すためには、追加の状態が必要なようです。

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

+0

この問題は一見したようにより複雑です。ドキュメントからは、wait関数が呼び出されるたびにコールバックが呼び出されるように思われます。 "効果: *のコールバックとして* thisと関連付けられた非同期の結果を持つfのコピーを格納するこれは既存の待機コールバックストアをその結果と共に置き換えます。 :: shared_futureがこの結果に関連付けられ、結果が準備されていない場合、f(* this)が呼び出されます。 –

関連する問題