如何在 pthread 中创建准确的纳秒延迟以及如何在不中断的情况下运行程序的 pthread 部分?
Posted
技术标签:
【中文标题】如何在 pthread 中创建准确的纳秒延迟以及如何在不中断的情况下运行程序的 pthread 部分?【英文标题】:How to create accurate nanosecond delay in a pthread and how to run a pthread part of the program without interruption? 【发布时间】:2022-01-19 11:56:06 【问题描述】:我是 C 编程的初学者。在下面的代码中,我们有两个 pthread。我希望在两个 pthread 同步后,根据用户的选择延迟其中一个。我希望这个延迟尽可能准确。在下面的代码中,我已经这样做了,但没有发生确切的延迟量。
但我还有一个问题,那就是如何强制 pthread 从头到尾不间断地运行程序的某个部分。
提前谢谢你。
代码:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/random.h>
#include <sys/time.h>
#include <math.h>
pthread_cond_t cond;
pthread_mutex_t cond_mutex;
unsigned int waiting;
struct timeval timeZero, timeOne, timeZeroBase, timeOneBase;
struct timespec tim, tim2;
int flag = 0;
void synchronize(void)
pthread_mutex_lock(&cond_mutex);
if (++waiting == 2)
pthread_cond_broadcast(&cond);
else
while (waiting != 2)
pthread_cond_wait(&cond, &cond_mutex);
pthread_mutex_unlock(&cond_mutex);
void *threadZero(void *_)
// ...
synchronize();
gettimeofday(&timeZeroBase, 0);
if(flag == 0)
nanosleep(&tim, &tim2);
gettimeofday(&timeZero, 0);
timeZero.tv_usec = timeZero.tv_usec - timeZeroBase.tv_usec;
// ...
return NULL;
void *threadOne(void *_)
// ...
synchronize();
gettimeofday(&timeOneBase, 0);
if(flag == 1)
nanosleep(&tim, &tim2);
gettimeofday(&timeOne, 0);
timeOne.tv_usec = timeOne.tv_usec - timeOneBase.tv_usec;
// ...
return NULL;
int main(void)
pthread_t zero, one;
tim.tv_sec = 0;
tim.tv_nsec = 50;
printf("Declare the number of function (0 or 1): ");
scanf("%d", &flag);
pthread_create(&zero, NULL, threadZero, NULL);
pthread_create(&one, NULL, threadOne, NULL);
// ...
pthread_join(zero, NULL);
pthread_join(one, NULL);
printf("\nReal delay (ns): %lu\n", (timeZero.tv_usec - timeOne.tv_usec));
return 0;
【问题讨论】:
什么是“精确的纳秒延迟”? ±多少?我认为您可以忘记使用任何类型的sleep
函数。忙碌等待可能是更好的选择。
当您说“纳秒延迟”时,您是指单个纳秒吗?那是不可能的。任何多任务系统的准确性都不是。如果您需要单纳秒分辨率的计时精度,您需要一个实时系统。
您对操作系统提出了很多要求。最好的办法是将线程绑定到特定的 CPU 内核,并限制所有线程(在整个操作系统上)使用该内核。您可能想要使用实时操作系统。这些都不是初学者的话题。
@Ted Lyngmo,我的意思是能够延迟几纳秒。例如,50 纳秒或 100 纳秒或更多。但是这个延迟应该尽可能准确。在上面的代码中,延迟并没有完全发生,我不知道该怎么办。
@Ted Lyngmo,非常感谢,我会试试的。
【参考方案1】:
可以提高准确性的一种方法是忙等待而不是休眠。
我创建了一个名为mysleep
的函数,它采用包含请求的睡眠时间的struct timespec*
。它检查当前时间并将请求的睡眠时间添加到该时间 - 然后旋转直到当前时间 >=
目标时间点。
但请注意:不能保证保持任何准确性。 通常会相当不错,但有时当操作系统暂停线程时,您会看到测量时间出现峰值。如果您不走运,校准中会出现这些尖峰之一,然后所有您的睡眠将完全关闭。您可以运行校准例程 100 次,然后选择中间值,以使这种不幸的情况不太可能发生。
#include <stdio.h>
#include <time.h>
static long calib; // used for calibrating mysleep()
void mysleep(const struct timespec *req)
struct timespec tp, now;
clock_gettime(CLOCK_MONOTONIC, &tp); // get current time point
// add the requested sleep time and remove the calibrated value
tp.tv_sec += req->tv_sec;
tp.tv_nsec += req->tv_nsec - calib;
if(tp.tv_nsec > 999999999)
tp.tv_nsec -= 1000000000;
++tp.tv_sec;
else if(tp.tv_nsec<0)
tp.tv_nsec += 1000000000;
--tp.tv_sec;
// busy-wait until the target time point is reached:
do
clock_gettime(CLOCK_MONOTONIC, &now);
while(now.tv_sec < tp.tv_sec ||
(now.tv_sec == tp.tv_sec && now.tv_nsec < tp.tv_nsec));
struct timespec get_diff(const struct timespec *start, struct timespec *end)
struct timespec temp;
if((end->tv_nsec - start->tv_nsec) < 0)
temp.tv_sec = end->tv_sec - start->tv_sec - 1;
temp.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec;
else
temp.tv_sec = end->tv_sec - start->tv_sec;
temp.tv_nsec = end->tv_nsec - start->tv_nsec;
return temp;
// A non-scientific calibration routine
void calibrate()
struct timespec start, end, sleep = 0;
calib = 0;
clock_gettime(CLOCK_MONOTONIC, &start);
mysleep(&sleep);
clock_gettime(CLOCK_MONOTONIC, &end);
struct timespec diff = get_diff(&start, &end);
calib = (diff.tv_sec * 1000000000 + diff.tv_nsec) / 2;
int main()
calibrate(); // must be done before using mysleep()
// use mysleep()
Demo
可能的输出(带有尖峰):
calib=157
should be close to 1000: 961
should be close to 1000: 931
should be close to 1000: 906
should be close to 1000: 926
should be close to 1000: 935
should be close to 1000: 930
should be close to 1000: 916
should be close to 1000: 932
should be close to 1000: 124441
should be close to 1000: 911
【讨论】:
以上是关于如何在 pthread 中创建准确的纳秒延迟以及如何在不中断的情况下运行程序的 pthread 部分?的主要内容,如果未能解决你的问题,请参考以下文章