boost :: future - wait_callback是否只能被调用一次?

时间:2012-02-20 01:25:27

标签: c++ boost-thread future

如果我在set_wait_callback上设置boost::unique_future,是否保证只运行一次?

我有点怀疑,因为在查看源代码时我会发现以下内容:

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)   引用此共享状态的异步返回对象将调用   调用等待函数的线程中的延迟函数

1 个答案:

答案 0 :(得分: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();
    }
}    

BTW,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));
    }

请你能为Boost Thread创建一个Trac票,这样这个问题不会丢失吗?