使用 usleep 控制循环时间
Control loop time with usleep
我尝试用usleep保证每个循环的执行时间为10ms,但有时会超过10ms。
我不知道如何解决这个问题,使用usleep和[=18是否合适=]gettimeofday 在这种情况下?
请帮我找出我错过了什么。
Result: 0.0127289
0.0136499
0.0151598
0.0114031
0.014801
double tvsecf(){
struct timeval tv;
double asec;
gettimeofday(&tv,NULL);
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;
return asec;
}
int main(){
double t1 ,t2;
t1 = tvsecf();
for(;;){
t2= tvsecf();
if(t2-t1 >= 0.01){
if(t2-t1 >= 0.011)
cout << t2-t1 <<endl;
t1 = tvsecf();
}
usleep(100);
}
}
The sleep may be lengthened slightly by any system activity or by the time spent processing the call or by the granularity of system timers.
如果您需要高分辨率:在 Unix 上使用 C(或 Linux)查看 this answer,其中解释了如何使用 clock_gettime.
来使用高分辨率计时器
编辑:如 Tobias 所述,nanosleep 可能是更好的选择:
Compared to sleep(3) and usleep(3), nanosleep() has the following
advantages: it provides a higher resolution for specifying the sleep
interval; POSIX.1 explicitly specifies that it does not interact with
signals; and it makes the task of resuming a sleep that has been
interrupted by a signal handler easier.
无法保证 10 毫秒的循环时间。
所有休眠功能至少在需要的时间内休眠。
对于便携式解决方案,请使用 std::this_thread::sleep_for
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
for (;;) {
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds{10});
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << "Waited " << elapsed.count() << " ms\n";
}
}
根据您要执行的操作,查看 Howard Hinnants 日期库。
为了防止循环开销(通常是未知的)不断累积错误,您可以休眠 until 时间 point,而不是 时间持续时间。使用 C++ 的 <chrono>
和 <thread>
库,这非常简单:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
auto t0 = steady_clock::now() + 10ms;
for (;;)
{
this_thread::sleep_until(t0);
t0 += 10ms;
}
}
可以通过更多调用 steady_clock::now()
来修饰它,以确定迭代之间的时间,也许更重要的是,平均 迭代时间:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
using dsec = duration<double>;
auto t0 = steady_clock::now() + 10ms;
auto t1 = steady_clock::now();
auto t2 = t1;
constexpr auto N = 1000;
dsec avg{0};
for (auto i = 0; i < N; ++i)
{
this_thread::sleep_until(t0);
t0 += 10ms;
t2 = steady_clock::now();
dsec delta = t2-t1;
std::cout << delta.count() << "s\n";
avg += delta;
t1 = t2;
}
avg /= N;
cout << "avg = " << avg.count() << "s\n";
}
上面我通过在循环中做更多的事情增加了循环开销。然而,循环仍然会每 10 毫秒唤醒 about。有时 OS 会延迟唤醒线程,但下次循环会自动调整自身以休眠更短的时间。因此平均迭代率自校正为 10ms。
在我的机器上这只是输出:
...
0.0102046s
0.0128338s
0.00700504s
0.0116826s
0.00785826s
0.0107023s
0.00912614s
0.0104725s
0.010489s
0.0112545s
0.00906409s
avg = 0.0100014s
我尝试用usleep保证每个循环的执行时间为10ms,但有时会超过10ms。
我不知道如何解决这个问题,使用usleep和[=18是否合适=]gettimeofday 在这种情况下?
请帮我找出我错过了什么。
Result: 0.0127289 0.0136499 0.0151598 0.0114031 0.014801
double tvsecf(){
struct timeval tv;
double asec;
gettimeofday(&tv,NULL);
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;
return asec;
}
int main(){
double t1 ,t2;
t1 = tvsecf();
for(;;){
t2= tvsecf();
if(t2-t1 >= 0.01){
if(t2-t1 >= 0.011)
cout << t2-t1 <<endl;
t1 = tvsecf();
}
usleep(100);
}
}
The sleep may be lengthened slightly by any system activity or by the time spent processing the call or by the granularity of system timers.
如果您需要高分辨率:在 Unix 上使用 C(或 Linux)查看 this answer,其中解释了如何使用 clock_gettime.
来使用高分辨率计时器编辑:如 Tobias 所述,nanosleep 可能是更好的选择:
Compared to sleep(3) and usleep(3), nanosleep() has the following
advantages: it provides a higher resolution for specifying the sleep
interval; POSIX.1 explicitly specifies that it does not interact with
signals; and it makes the task of resuming a sleep that has been
interrupted by a signal handler easier.
无法保证 10 毫秒的循环时间。 所有休眠功能至少在需要的时间内休眠。 对于便携式解决方案,请使用 std::this_thread::sleep_for
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
for (;;) {
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds{10});
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << "Waited " << elapsed.count() << " ms\n";
}
}
根据您要执行的操作,查看 Howard Hinnants 日期库。
为了防止循环开销(通常是未知的)不断累积错误,您可以休眠 until 时间 point,而不是 时间持续时间。使用 C++ 的 <chrono>
和 <thread>
库,这非常简单:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
auto t0 = steady_clock::now() + 10ms;
for (;;)
{
this_thread::sleep_until(t0);
t0 += 10ms;
}
}
可以通过更多调用 steady_clock::now()
来修饰它,以确定迭代之间的时间,也许更重要的是,平均 迭代时间:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
using dsec = duration<double>;
auto t0 = steady_clock::now() + 10ms;
auto t1 = steady_clock::now();
auto t2 = t1;
constexpr auto N = 1000;
dsec avg{0};
for (auto i = 0; i < N; ++i)
{
this_thread::sleep_until(t0);
t0 += 10ms;
t2 = steady_clock::now();
dsec delta = t2-t1;
std::cout << delta.count() << "s\n";
avg += delta;
t1 = t2;
}
avg /= N;
cout << "avg = " << avg.count() << "s\n";
}
上面我通过在循环中做更多的事情增加了循环开销。然而,循环仍然会每 10 毫秒唤醒 about。有时 OS 会延迟唤醒线程,但下次循环会自动调整自身以休眠更短的时间。因此平均迭代率自校正为 10ms。
在我的机器上这只是输出:
...
0.0102046s
0.0128338s
0.00700504s
0.0116826s
0.00785826s
0.0107023s
0.00912614s
0.0104725s
0.010489s
0.0112545s
0.00906409s
avg = 0.0100014s