以下程序根据使用的睡眠机制运行不同。
#include <ppltasks.h>
#include <chrono>
#include <thread>
#include <iostream>
#include <atomic>
#include <windows.h>
using namespace std;
#define MODERN_MAN
int main()
{
atomic<int> cnt;
concurrency::task_group tg;
for (int i =0; i<1000; ++i )
{
tg.run([&cnt](){cout << "."; cnt++;
#ifdef MODERN_MAN
this_thread::sleep_for(chrono::seconds(5));
#else
Sleep(5000);
#endif
});
}
tg.wait();
cout << cnt;
return 0;
}
与sleep_for
的区别在于我看到的任务以1睡眠不会阻止其他人运行的方式进行安排。
根据我看到的Sleep
,他们阻止了进一步的任务。
我的问题是:
a)PPL线程池如何能够使巧妙的技巧使其能够解决sleep_for
(我认为这是一个告诉操作系统的系统调用(将此线程放在非活动线程列表中x秒)
b)我在这里看到的行为是否有sleep_for
保证(也就是定义我不会得到与Sleep
相同的行为)
答案 0 :(得分:4)
a)PPL线程池如何能够实现巧妙的技巧,使其能够解决
sleep_for
(我认为这是一个告诉操作系统的系统调用(将此线程放入非活动线程列表中x秒)< / p>
在Microsoft VC ++ 2012上,C ++标准线程库和PPL基于具有Concurrency Runtime(ConcRT)的cooperative and work-stealing scheduler实现。
因此,ConcRT调度程序可以处理任务包括std::this_thread::sleep_for
聪明的方式。
b)我在这里看到的行为是否保证sleep_for(也就是定义我不会得到与
Sleep
相同的行为)
也许不。 Sleep
是原生的WinAPI,我猜ConRT调度程序不能合作对待它。
附注:Microsoft在Windows 7 / Server 2008 R2 64位版本上说ConcRT use User-mode scueduling(UMS)。可以在这样的平台上改变行为......
答案 1 :(得分:2)
查看相关标题(即#include <thread>
)可能会提供信息,并了解它的不同之处。例如,这是sleep_for()
定义:
template<class _Rep, class _Period> inline
void sleep_for(const chrono::duration<_Rep, _Period>& _Rel_time)
{
// sleep for duration
stdext::threads::xtime _Tgt = _To_xtime(_Rel_time);
sleep_until(&_Tgt);
}
使用sleep_until()
的“绝对时间”重载:
inline void sleep_until(const stdext::threads::xtime *_Abs_time)
{
// sleep until _Abs_time
if (::Concurrency::details::_CurrentScheduler::_Id() != -1)
{
stdext::threads::xtime _Now;
stdext::threads::xtime_get(&_Now, stdext::threads::TIME_UTC);
::Concurrency::wait(_Xtime_diff_to_millis2(_Abs_time, &_Now));
return;
}
_Thrd_sleep(_Abs_time);
}
在CRT调用_Thrd_sleep()
时,路径停止,并且要弄清楚条件代码的作用并不容易。看起来它对非默认调度程序采取不同的操作,但我现在看不清楚原因。在任何情况下,也许这已经消除了一些光?
答案 2 :(得分:1)
一个原因可能是两种睡眠方法的准确性不同。要找出你应该测试 - 在你的平台上 - 通过测量两个相邻Sleep(0)
和两个相邻Sleep(1)
之间的时间和sleep_for()
请注意,定时器值的精度与实际精度之间可能存在显着差异。例如。 clock()提供毫秒精度,但是 - 在我的机器上 - 精度为15ms(平均)。