【问题标题】:passing bool by reference and use its latest value通过引用传递 bool 并使用其最新值
【发布时间】:2013-12-03 21:36:52
【问题描述】:

我有以下代码:

MyClass::aMethod()
{
    ...
    bool isStarted = false;

    boost::thread(boost::bind(&MyClass::CheckTimeoutThread, this, isStarted));

    ...//some time later
    isStarted = true;
    ...
}

MyClass::checkTimeoutThread(bool &isStarted)
{
    ...//some code here
    while(anotherFlag)
    {
        ...//do something
        if(isStarted)//ALWAYS THE INITIAL VALUE OF FALSE
        {
        }
        ...
    }
}

我预计 isStarted 变量可以用作标志,但我错了,或者我做错了什么。

【问题讨论】:

    标签: c++ boost thread-synchronization


    【解决方案1】:

    boost::thread 将存储其参数的副本。但是您可以在boost::ref 的帮助下通过传递reference_wrapper 来模拟引用。另请注意,您无需致电boost::bind

    boost::thread t(&MyClass::CheckTimeoutThread, this, boost::ref(isStarted));
    

    但请注意,您现在在 isStarted 上有一个比赛条件。如果您的平台上可用,您需要使用互斥锁同步访问它,或者使用原子类型(如果您有 C++11,那么您可以使用std::atomic<bool>,正如@PeteBecker 所建议的那样。)

    编辑 显然,以上所有假设都假设isStated 的寿命至少与使用它的thread 一样长。实际上,这意味着线程必须在aMethod 返回时完成。或者,您可以将isStarted 设为数据成员。但是您仍然必须确保在 MyClass 析构函数破坏它之前加入线程。

    【讨论】:

    • 删除我的答案并支持你的答案:没有注意到c++11 的缺席。
    • 何时调用 boost::bind 何时不调用?我们到处叫它。
    • 解决了第一个问题。第二个是在一个线程中对isStarted 的写入和在另一个线程中的读取不同步,因此不能保证第二个线程会看到更新的值。在 C++11 中,这需要std::atomic<bool>
    • @5YrsLaterDBA 例如如果你需要一个可调用对象,boost::function<void()> f = boost::bind.....
    • @PeteBecker 你是对的。就我而言,该检查并不重要,但无论如何都应该同步。如果不同步,值可能不是最新的值是唯一的问题,或者当两个线程尝试同时访问同一位置时可能会导致崩溃?
    【解决方案2】:

    最大的问题(除了 std::refboost::ref 需要传递对 thread 的引用)是您传递 对临时的引用

    MyClass::aMethod()
    {
        ...
        bool isStarted = false;
    
    }
    
    /// Oops at the end of the method, `isStarted` no longer lives 
    

    任何通过陈旧引用的访问都是在控制离开aMethod

    之后的未定义行为

    我可以建议使用适当的同步:See it Live on Coliru

    #include <thread>
    #include <mutex>
    #include <condition_variable>
    #include <iostream>
    
    struct X
    {
        std::condition_variable cv;
        std::mutex mx;
        bool isStarted;
        std::thread worker;
    
        X() : isStarted(false) {}
    
        void aMethod()
        {
            worker = std::thread(&X::Worker, this);
    
            std::this_thread::sleep_for(std::chrono::seconds(1));
    
            {
                std::cout << "signalling worker\n";
                std::unique_lock<std::mutex> lock(mx);
                isStarted = true;
                cv.notify_one();
            }
    
            worker.join();
            isStarted = false;
        }
    
        void Worker()
        {
            std::unique_lock<std::mutex> lock(mx);
            std::cout << "worker ready\n";
            cv.wait(lock, [this] { return isStarted; });
            std::cout << "worker started\n";
    
            std::cout << "worker done\n";
        }
    };
    
    int main()
    {
        X o;
        o.aMethod();
    }
    

    注意

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-26
      • 1970-01-01
      • 2013-07-22
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多