当与chrono :: duration <float>一起使用时,条件变量不会被唤醒

时间:2017-12-10 22:50:14

标签: c++ chrono condition-variable

将条件变量设置为等待chrono::duration<float>类型的持续时间会导致条件变量没有被唤醒,而chrono::duration<int>则会唤醒它。

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <chrono>

using namespace std;

void int_version()
{
   mutex my_mutex;
   unique_lock<mutex> my_lock(my_mutex);
   condition_variable my_cv;

   chrono::duration<int> my_duration(5);

   // this_thread::sleep_for(my_duration);
   my_cv.wait_for(my_lock, my_duration);
   cout << "Int version finished" << endl;;
}

void float_version()
{
   mutex my_mutex;
   unique_lock<mutex> my_lock(my_mutex);
   condition_variable my_cv;

   chrono::duration<float> my_duration(5);

   // this_thread::sleep_for(my_duration);
   my_cv.wait_for(my_lock, my_duration);
   cout << "Float version finished" << endl;;
}

int main()
{
    thread float_thread(float_version);
    float_thread.detach();

    thread int_thread(int_version);
    int_thread.detach();

    this_thread::sleep_for(chrono::seconds(10));
    cout << "10 secs elapsed" << endl;
}

我无法仅使用this_thread::sleep_for重现此行为,在这种情况下,两个版本都可以正常唤醒。

此外,有时候,不是没有醒来,浮动版本会立即醒来,而不会等待5秒。我想这可能是一个虚假的唤醒,但我怀疑它,因为它从来没有发生在int版本,并从我做过的几个测试,当我试图把它在一个while循环中检查虚假的唤醒它似乎经常被唤醒。

那发生了什么?我是否误解了chrono::duration<float>的明显内容?我的条件变量有问题吗?有线程吗?

使用GCC 7.2和-std = c ++ 17 -pthread在Ubuntu 16.04上编译。

2 个答案:

答案 0 :(得分:4)

我现在认为这毕竟不是libstdc ++错误。

该标准规定std::condition_variable::wait_for(rel_time)必须与wait_until(chrono::steady_clock::now() + rel_time)完全相同。

问题在于steady_clock可能具有很高的分辨率(标准未指定,但是libstdc ++使用std::chrono::nanoseconds作为steady_clock::duration类型)。当rel_time的类型为duration<float>时,steady_clock::now() + rel_time的结果为duration<float, steady_clock::period>。对于libstdc ++,该时间段为std::nano,这意味着结果为float,其中保存着自1970年1月1日以来的纳秒数。这是很多纳秒。 float所能代表的范围远不止这些。 float最多只能精确表示2 23 的整数,比1970年以来的纳秒数小

结果是float的值必须四舍五入,并且可能是steady_clock::now()前几秒钟的值,在这种情况下,超时立即发生(而不是等待一秒钟)。或者,可能是steady_clock::now()之后几秒钟,在这种情况下,超时发生的时间要比一秒钟要晚。

因此,如果要在具有高分辨率时间(例如来自高分辨率时钟的时间)的算术中使用chrono::duration<float>,则基本上它不是有用的类型。 std::chrono::system_clockstd::chrono::steady_clock的分辨率取决于实现,因此,您不应假定可以将chrono::duration<float>与系统提供的时钟一起安全使用。

它可以在GCC 6.5和7.4及更高版本中使用,但这仅是因为我们故意做一些与标准要求不同的事情。这意味着该修补程序是非标准的且不可移植,因此仍应谨慎使用duration<float>

答案 1 :(得分:2)

您的密码没有问题。它是libstdc ++的bug