Hoo*_*och 10 c++ winapi multithreading sleep loops
我有运行循环的线程.我需要每5ms运行一次循环(1ms错误).我知道Sleep()函数不精确.
你有什么建议吗?
更新.我不能以其他方式做到这一点.在循环结束时,我需要某种睡眠.我也不想加载100%的CPU.
Arn*_*rno 12
不要在这里使用纺纱.使用标准方法可以达到所要求的分辨率和准确度.
Sleep()
当系统中断周期设置为以该高频率工作时,您可以使用大约1 ms的周期.查看Sleep()的描述以获取详细信息,特别是具有获取和设置定时器分辨率的多媒体定时器,以获取有关如何设置系统中断周期的详细信息.当正确实施时,这种方法可获得的精度在几微秒范围内.
我怀疑你的循环也在做其他事情.因此,我怀疑你想要一个5毫秒的总时间,这将是Sleep()
你在循环中花在其他东西上的剩余时间的总和.
对于这种情况,我建议使用Waitable Timer Objects,但这些计时器也依赖于多媒体计时器API的设置.我已经给了相关功能的概述更高的精确定时在这里.在这里可以找到更高深度的高精度定时.
为了获得更加准确和可靠的计时,您可能需要查看process priority classes
和thread priorities
.关于Sleep()准确性的另一个答案就是这个.
但是,是否可以获得Sleep()
精确的5 ms延迟取决于系统硬件.某些系统允许您以每秒1024个中断运行(由多媒体计时器API设置).这相当于0.9765625毫秒的周期.因此,您最接近的是4.8828125 ms.其他人允许更接近,特别是因为Windows 7在硬件提供上运行时的时间显着改善high resolution event timers
.请参阅关于 MSDN和高精度事件计时器的定时器.
摘要:将多媒体计时器设置为以最大频率运行并使用等待计时器.
Shi*_*hah 12
我一直在寻找适合实时应用的轻量级跨平台睡眠功能(即高分辨率/高精度和可靠性).以下是我的发现:
安排基础知识
放弃CPU然后取回它是昂贵的.根据这篇文章,Linux上的调度程序延迟可能在10到30毫秒之间.因此,如果您需要以高精度睡眠不到10毫秒,那么您需要使用特殊的操作系统特定API.通常的C++ 11 std :: this_thread :: sleep_for不是高分辨率睡眠.例如,在我的机器上,快速测试显示,当我要求它睡眠仅1ms时,它经常睡眠至少3ms.
Linux的
最流行的解决方案似乎是nanosleep()API.但是,如果您希望<2ms睡眠时的分辨率高于您需要使用sched_setscheduler调用来设置线程/进程以进行实时调度.如果你不是nanosleep()就像过时的usleep一样,分辨率约为10ms.另一种可能性是使用警报.
视窗
这里的解决方案是使用其他人建议的多媒体时间.如果你想在Windows上模拟Linux的nanosleep(),下面是如何(原始参考).再次注意,如果在循环中调用sleep(),则不需要反复执行CreateWaitableTimer().
#include <windows.h> /* WinAPI */
/* Windows sleep in 100ns units */
BOOLEAN nanosleep(LONGLONG ns){
/* Declarations */
HANDLE timer; /* Timer handle */
LARGE_INTEGER li; /* Time defintion */
/* Create timer */
if(!(timer = CreateWaitableTimer(NULL, TRUE, NULL)))
return FALSE;
/* Set timer properties */
li.QuadPart = -ns;
if(!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)){
CloseHandle(timer);
return FALSE;
}
/* Start & wait for timer */
WaitForSingleObject(timer, INFINITE);
/* Clean resources */
CloseHandle(timer);
/* Slept without problems */
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
跨平台代码
这是为Linux,Windows和Apple平台实现睡眠的time_util.cc.但是请注意,它没有像我上面提到的那样使用sched_setscheduler设置实时模式,所以如果你想使用<2ms,那么你需要另外做的事情.您可以做的另一项改进是,如果您在某个循环中调用sleep,则应避免一遍又一遍地调用CreateWaitableTimer for Windows版本.有关如何执行此操作,请参阅此处的示例.
#include "time_util.h"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#else
# include <time.h>
# include <errno.h>
# ifdef __APPLE__
# include <mach/clock.h>
# include <mach/mach.h>
# endif
#endif // _WIN32
/**********************************=> unix ************************************/
#ifndef _WIN32
void SleepInMs(uint32 ms) {
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = ms % 1000 * 1000000;
while (nanosleep(&ts, &ts) == -1 && errno == EINTR);
}
void SleepInUs(uint32 us) {
struct timespec ts;
ts.tv_sec = us / 1000000;
ts.tv_nsec = us % 1000000 * 1000;
while (nanosleep(&ts, &ts) == -1 && errno == EINTR);
}
#ifndef __APPLE__
uint64 NowInUs() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return static_cast<uint64>(now.tv_sec) * 1000000 + now.tv_nsec / 1000;
}
#else // mac
uint64 NowInUs() {
clock_serv_t cs;
mach_timespec_t ts;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs);
clock_get_time(cs, &ts);
mach_port_deallocate(mach_task_self(), cs);
return static_cast<uint64>(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
}
#endif // __APPLE__
#endif // _WIN32
/************************************ unix <=**********************************/
/**********************************=> win *************************************/
#ifdef _WIN32
void SleepInMs(uint32 ms) {
::Sleep(ms);
}
void SleepInUs(uint32 us) {
::LARGE_INTEGER ft;
ft.QuadPart = -static_cast<int64>(us * 10); // '-' using relative time
::HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
::SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
::WaitForSingleObject(timer, INFINITE);
::CloseHandle(timer);
}
static inline uint64 GetPerfFrequency() {
::LARGE_INTEGER freq;
::QueryPerformanceFrequency(&freq);
return freq.QuadPart;
}
static inline uint64 PerfFrequency() {
static uint64 xFreq = GetPerfFrequency();
return xFreq;
}
static inline uint64 PerfCounter() {
::LARGE_INTEGER counter;
::QueryPerformanceCounter(&counter);
return counter.QuadPart;
}
uint64 NowInUs() {
return static_cast<uint64>(
static_cast<double>(PerfCounter()) * 1000000 / PerfFrequency());
}
#endif // _WIN32
Run Code Online (Sandbox Code Playgroud)
还可以在此处找到另一个更完整的跨平台代码.
另一个快速解决方
您可能已经注意到,上面的代码不再是非常轻量级的.它需要包括Windows标题,如果您正在开发仅标题库,那么可能不太理想.如果您需要睡眠时间少于2毫秒并且您不是非常热衷于使用操作系统代码,那么您可以使用以下简单的解决方案,这是跨平台的,并且在我的测试中运行良好.请记住,您现在没有使用经过大量优化的操作系统代码,这可能会更好地节省电源和管理CPU资源.
typedef std::chrono::high_resolution_clock clock;
template <typename T>
using duration = std::chrono::duration<T>;
static void sleep_for(double dt)
{
static constexpr duration<double> MinSleepDuration(0);
clock::time_point start = clock::now();
while (duration<double>(clock::now() - start).count() < dt) {
std::this_thread::sleep_for(MinSleepDuration);
}
}
Run Code Online (Sandbox Code Playgroud)
相关问题
根据问题标签,我想您在Windows上。看看Multimedia Timers,他们在1ms以下发布精度。另一个选择是使用自旋锁,但是这基本上将使CPU核心保持最大使用率。
归档时间: |
|
查看次数: |
16467 次 |
最近记录: |