运行 线程每 20 毫秒定期失败

Running thread periodically every 20 ms fails

目前我正在为一个嵌入式应用程序编程,该应用程序会定期从传感器读取值。我希望每 20 毫秒读取一次。

我正在使用这个 tutorial

struct periodic_info {
    int sig;
    sigset_t alarm_sig;
};

static int make_periodic(int unsigned period, struct periodic_info *info)
{
    static int next_sig;
    int ret;
    unsigned int ns;
    unsigned int sec;
    struct sigevent sigev;
    timer_t timer_id;
    struct itimerspec itval;

    /* Initialise next_sig first time through. We can't use static
       initialisation because SIGRTMIN is a function call, not a constant */
    if (next_sig == 0)
        next_sig = SIGRTMIN;
    /* Check that we have not run out of signals */
    if (next_sig > SIGRTMAX)
        return -1;
    info->sig = next_sig;
    next_sig++;
    /* Create the signal mask that will be used in wait_period */
    sigemptyset(&(info->alarm_sig));
    sigaddset(&(info->alarm_sig), info->sig);

    /* Create a timer that will generate the signal we have chosen */
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = info->sig;
    sigev.sigev_value.sival_ptr = (void *)&timer_id;
    ret = timer_create(CLOCK_MONOTONIC, &sigev, &timer_id);
    if (ret == -1)
        return ret;

    /* Make the timer periodic */
    sec = period / 1000000;
    ns = (period - (sec * 1000000)) * 1000;
    itval.it_interval.tv_sec = sec;
    itval.it_interval.tv_nsec = ns;
    itval.it_value.tv_sec = sec;
    itval.it_value.tv_nsec = ns;
    ret = timer_settime(timer_id, 0, &itval, NULL);
    return ret;
}

static void wait_period(struct periodic_info *info)
{
    int sig;
    sigwait(&(info->alarm_sig), &sig);
}

static int thread_1_count;

主线:

int main(){



    pthread_t t_1;
    pthread_t t_2;
    sigset_t alarm_sig;
    int i;

    printf("Periodic threads using POSIX timers\n");

    /* Block all real time signals so they can be used for the timers.
       Note: this has to be done in main() before any threads are created
       so they all inherit the same mask. Doing it later is subject to
       race conditions */
    sigemptyset(&alarm_sig);
    for (i = SIGRTMIN; i <= SIGRTMAX; i++)
        sigaddset(&alarm_sig, i);
    sigprocmask(SIG_BLOCK, &alarm_sig, NULL);

    pthread_create(&t_1, NULL, thread_1, NULL);
    sleep(10);
    printf("Thread 1 %d iterations\n", thread_1_count);
    return 0;

我现在的问题,我用高分辨率时钟测量时间,周期为 20ms。

static void *thread_1(void *arg)
{
    struct periodic_info info;

    printf("Thread 1 period 10ms\n");
    make_periodic(20000, &info);
    while (1) {
        auto start = std::chrono::high_resolution_clock::now();
        printf("Hello\n");
        thread_1_count++;
        wait_period(&info);
        auto finish = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms_double = finish - start;
        std::cout << ms_double.count() << "ms\n";
    }
    return NULL;
}

我得到的输出是:

...
19.8556ms
19.8587ms
19.8556ms
19.8543ms
19.8562ms
19.8809ms
19.7592ms
19.8381ms
19.8302ms
19.8437ms
...

所以我的问题是,为什么时间比我的经期时间短,我做错了什么?

为了更准确,每次迭代不要花费两次时间,保留最后一个值,如下所示:

static void *thread_1(void *arg)
{
    struct periodic_info info;

    printf("Thread 1 period 10ms\n");
    make_periodic(20000, &info);
    auto start = std::chrono::high_resolution_clock::now();
    while (1) {
        wait_period(&info);
  
        auto finish = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms_double = finish - start;
        std::cout << ms_double.count() << "ms\n";
        start = finish;
    }
    return NULL;
}

这样的话,时间的测量会更加准确。