clock_nanosleep():它忽略时间规格结构

时间:2021-01-19 13:16:06

标签: c posix

我正在尝试创建这个基本的 clock_nanosleep 示例,但它不会暂停我不断打印数字的 for 循环。如果我取消对 //t.tv_nsec = s/1000000000; 的注释,将不会打印任何内容,但会运行 for 循环。

// POSIX.1-2017 is what compiler is confined to.
#define _XOPEN_SOURCE 700

// C headers.
#include <stdint.h>
#include <time.h>
#include <stdio.h>
   
int main(int argc, char *argv[])
{
    // Counter.
    uint8_t i;

    // Time.
    int s = 1;

    // Create a timespec structure and calculate it's members.
    struct timespec t;
    t.tv_sec = s;
    //t.tv_nsec = s/1000000000;

    // Set flags i.e. TIMER_ABSTIME to 0 to use relative instead of absolute time.
    int flags = 0;

    // Choose the clock i.e. CLOCK_MONOTONIC is a "clock_id" for the clock started at system start.
    int clock_id = CLOCK_MONOTONIC;

    for(i = 0; i < 256; i++){
        printf("%d", i);

        // Because last argument is NULL in case of error, remaining time is not stored in "t".
        clock_nanosleep(clock_id, flags, &t, NULL);
    }

    return 0;

}

我完全不知道为什么这不起作用。 POSIX 声明:

<块引用>

int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp);

如果标志中没有设置标志 TIMER_ABSTIME 参数,clock_nanosleep() 函数将导致当前 线程暂停执行,直到时间间隔 rqtp 参数指定的时间已过,或者信号已传递 到调用线程,它的动作是调用一个信号捕获 函数,否则进程终止。

我确保标志已清零。我设置了 rqtp,即 &t

<块引用>

用于测量的时钟 时间应为 clock_id 指定的时钟。

我确实使用了 CLOCK_MONOTONIC

<块引用>

如果 clock_nanosleep() 函数返回,因为它已经 被信号中断,返回相应的错误 价值。对于相对 clock_nanosleep() 函数,如果 rmtp 参数是非 NULL,它引用的 timespec 结构应该是 更新以包含间隔中剩余的时间量( 请求的时间减去实际睡觉的时间)。 rqtprmtp 参数可以指向同一个对象。如果 rmtp 参数是 NULL, 剩余时间不返还。绝对clock_nanosleep() 函数对 rmtp 引用的结构没有影响。

我还将最后一个参数设置为 NULL,以便在 clock_naanosleep() 被任何信号中断时不存储剩余时间。

那么为什么这不起作用?

2 个答案:

答案 0 :(得分:2)

在这种情况下,您应该始终检查实际的返回值是什么,在这种情况下将是 EINVAL,因为 t.tv.nsec 未初始化。

使用:

struct timespec t = {
    .tv_sec = s,
};

正确初始化所有字段,即使是您不打算使用的字段。

答案 1 :(得分:2)

局部变量不会被隐式初始化。因此,如果您不设置 t.tv_nsec,它可以包含任何值。如果该值恰好在 0 - 999999999 的范围之外,则 clock_nanosleep 将立即返回错误代码。

当您设置 t.tv_nsec 时看不到任何输出的原因是因为您的打印方式:

 printf("%d", i);

您没有在输出中包含换行符。 stdout 流是行缓冲的,因此它不会自动将输出流刷新到控制台。将 \n 添加到格式字符串的末尾,您将看到打印出来的行。