【问题标题】:boost thread and try_join_for gives different output each timeboost thread 和 try_join_for 每次都会给出不同的输出
【发布时间】:2014-04-10 14:49:11
【问题描述】:

假设我有以下代码:

#include <boost/chrono.hpp>
#include <boost/thread.hpp>

#include <iostream>

int main()
{
  boost::thread thd([]{ std::cout << "str \n"; });

  boost::this_thread::sleep_for(boost::chrono::seconds(3));

  if (thd.try_join_for(boost::chrono::nanoseconds(1)))
  {
    std::cout << "Finished \n";
  }
  else
  {
    std::cout << "Running \n";
  }
}

每次启动此程序时,MSVC-12.0 和 boost 1.55 都会给我不同的输出。例如,

str
Finished

str
Finished

str
Running

当我将 boost::chrono::nanoseconds 更改为 boost::chrono::microseconds 时,输出看起来与预期一样。

为什么?我究竟做错了什么?它是boost库中的错误吗?在 boost bug tracker 中是否有关于 in 的票?

提前致谢。

【问题讨论】:

    标签: c++ boost boost-thread


    【解决方案1】:

    你的程序只是有一个比赛,很可能是因为 1 纳秒非常短。

    try_join_for 是通过调用try_join_until 实现的,该函数将尝试加入,直到达到某个时间点:

    // I stripped some unrelated template stuff from the code
    //  to make it more readable
    
    bool try_join_for(const chrono::duration& rel_time)
    {
      return try_join_until(chrono::steady_clock::now() + rel_time);
    }
    
    bool try_join_until(const chrono::time_point& t)
    {
      system_clock::time_point     s_now = system_clock::now();
      bool joined= false;
      do {
        Clock::duration   d = ceil<nanoseconds>(t-Clock::now());
        if (d <= Clock::duration::zero())
            return false; // in case the Clock::time_point t is already reached
        // only here we attempt to join for the first time:
        joined = try_join_until(s_now + d);
      } while (! joined);
      return true;
    }
    

    现在的问题是try_join_until 将在尝试加入之前检查是否已达到请求的时间点。如您所见,它需要对clock::now() 执行另外两次调用,并进行一些计算以将获得的值与用户给出的截止日期进行比较。这可能会或可能不会在时钟跳出给定的 1 纳秒截止日期之前完成,从而导致输出的不可预测性。

    请注意,一般来说,像这样的依赖于时间的代码是脆弱的。即使有毫秒级的超时,如果您在执行过程中被抢占,并且 CPU 负载很高,在极少数情况下您可能会错过最后期限。因此,请务必始终谨慎选择截止日期,切勿假设截止日期在所有可能的情况下都足够大。

    【讨论】:

    • 不错的答案:我想知道“比赛”,因为在加入尝试之前有三秒钟的延迟。但比赛不是与其他线程有关,而是与try_join_until() 中的计时器有关。
    【解决方案2】:

    只调用.join() 有什么问题?如果您坚持可以在加入前检查:

    #include <boost/chrono.hpp>
    #include <boost/thread.hpp>
    
    #include <iostream>
    
    int main()
    {
      boost::thread thd([]{ std::cout << "str\n"; });
      boost::this_thread::sleep_for(boost::chrono::seconds(3));
    
      if (thd.joinable())
          thd.join();
    }
    

    请注意,如果您在程序退出之前未能加入线程,则无论如何行为都是未定义的。使用

    • 期货,
    • 条件变量或
    • 信号量

    如果这是您试图监控的内容,则表示作业完成。

    【讨论】:

      猜你喜欢
      • 2018-06-10
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 2016-07-27
      • 1970-01-01
      • 2018-08-02
      • 1970-01-01
      相关资源
      最近更新 更多