将条件变量设置为等待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上编译。
答案 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_clock
和std::chrono::steady_clock
的分辨率取决于实现,因此,您不应假定可以将chrono::duration<float>
与系统提供的时钟一起安全使用。
它可以在GCC 6.5和7.4及更高版本中使用,但这仅是因为我们故意做一些与标准要求不同的事情。这意味着该修补程序是非标准的且不可移植,因此仍应谨慎使用duration<float>
。
答案 1 :(得分:2)
您的密码没有问题。它是libstdc ++的bug。