拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 如何在pthread中创建精确的纳秒延迟以及如何不间断地运行程序的pthread部分?

如何在pthread中创建精确的纳秒延迟以及如何不间断地运行程序的pthread部分?

白鹭 - 2022-03-08 2149 0 0

我是 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;
}

uj5u.com热心网友回复:

可以提高准确性的一种方法是忙等待而不是睡眠。

我创建了一个名为的函式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()
}

演示

可能的输出(带尖峰):

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
标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *