2012-02-20 113 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

相关问题