gpt4 book ai didi

C、clock_gettime,返回了不正确的纳秒值?

转载 作者:行者123 更新时间:2023-11-30 16:42:04 24 4
gpt4 key购买 nike

我正在编写一个简单的程序,它检查耗时是否超过 1 秒。我使用clock_gettime()获取开始时间,然后调用sleep(5),获取新时间并检查差异是否大于1;我睡了 5 秒,那么它应该大于 5,但我的程序打印了一个奇怪的结果。

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int main()
{
struct timespec tv1,tv3,expected;
struct timespec nano1;

tv1.tv_nsec = 0;
tv3.tv_nsec = 0;

expected.tv_nsec = 400000;

if(clock_gettime(CLOCK_MONOTONIC,&tv3) == -1){
perror(NULL);
}

sleep(5);

if(clock_gettime(CLOCK_MONOTONIC,&tv1) == -1){
perror(NULL);
}


long nsec = tv1.tv_nsec - tv3.tv_nsec;

if(nsec>expected.tv_nsec){
printf("nsec runned: %ld nsec timeout: %ld\n",nsec,expected.tv_nsec);
}


printf("elapsed nanoseconds: %ld\n",nsec);


if((nsec>expected.tv_nsec))
printf("expired timer\n");

else
printf("not expired timer\n");

exit(EXIT_SUCCESS);
}

我的程序的输出是:

“经过的纳秒:145130”和“未过期超时”

问题出在哪里?

最佳答案

struct timespec 中表示的时间有两个组成部分:

  • tv_sec — 一个time_t整数秒值。
  • tv_nsec — 纳秒数的 32 位整数,0..999,999,999

您的计算没有考虑 tv_sec 之间的差异值(value)观。纳秒值之间的差异如您所说的那么大,这有点令人惊讶,但绝非不可能。要获得全部差异,您需要考虑 tv_sectv_nsec组件。

sub_timespec()

您可以使用如下函数减去两个值(以获得差值):

enum { NS_PER_SECOND = 1000000000 };

void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td)
{
td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
td->tv_sec = t2.tv_sec - t1.tv_sec;
if (td->tv_sec > 0 && td->tv_nsec < 0)
{
td->tv_nsec += NS_PER_SECOND;
td->tv_sec--;
}
else if (td->tv_sec < 0 && td->tv_nsec > 0)
{
td->tv_nsec -= NS_PER_SECOND;
td->tv_sec++;
}
}

fmt_timespec

您可以使用如下函数将其格式化为具有指定小数位数的浮点值:

int fmt_timespec(const struct timespec *value, int dp, char *buffer, size_t buflen)
{
assert(value != 0 && buffer != 0 && buflen != 0);
if (value == 0 || buffer == 0 || buflen == 0)
{
errno = EINVAL;
return -1;
}
assert(dp >= 0 && dp <= 9);
if (dp < 0 || dp > 9)
{
errno = EINVAL;
return -1;
}
if ((value->tv_sec > 0 && value->tv_nsec < 0) ||
(value->tv_sec < 0 && value->tv_nsec > 0))
{
/* Non-zero components of struct timespec must have same sign */
errno = EINVAL;
return -1;
}

int len;
if (dp == 0)
len = snprintf(buffer, buflen, "%ld", value->tv_sec);
else
{
long nsec = value->tv_nsec;
long secs = value->tv_sec;
const char *sign = (secs < 0 || (secs == 0 && nsec < 0)) ? "-" : "";
if (secs < 0)
secs = -secs;
if (nsec < 0)
nsec = -nsec;
for (int i = 0; i < 9 - dp; i++)
nsec /= 10;
len = snprintf(buffer, buflen, "%s%ld.%.*ld", sign, secs, dp, nsec);
}
if (len > 0 && (size_t)len < buflen)
return len;
errno = EINVAL;
return -1;
}
<小时/>

相关代码的修订版本

标题time_io.h声明 struct timespec 的格式和扫描功能; time_math.h header 声明了加法和减法函数struct timespec值(value)观。拥有如此多的 header 可能对代码进行了过度划分。

#include "time_io.h"
#include "time_math.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

enum { NS_PER_SECOND = 1000000000 };

int main(void)
{
struct timespec tv3;
if (clock_gettime(CLOCK_MONOTONIC, &tv3) == -1)
perror("clock_gettime()");

sleep(5);

struct timespec tv1;
if (clock_gettime(CLOCK_MONOTONIC, &tv1) == -1)
perror("clock_gettime()");

struct timespec td;
sub_timespec(tv3, tv1, &td);

int64_t ts_in_ns = td.tv_sec * NS_PER_SECOND + td.tv_nsec;

char buffer[32];
fmt_timespec(&td, 9, buffer, sizeof(buffer));

printf("Elapsed time: %s (%" PRId64 " nanoseconds)\n", buffer, ts_in_ns);

return 0;
}

运行示例:

Elapsed time: 5.005192000 (5005192000 nanoseconds)

在运行 macOS Sierra 10.12.6 的 Mac 上(最终有 clock_gettime() - 早期版本的 Mac OS X 不支持它),分辨率为 clock_gettime()是 1000 纳秒,实际上是微秒。因此,在 Mac 上最后 3 位小数始终为零。

add_timespec()

为了完整起见,您可以添加两个 struct timespec值:

void add_timespec(struct timespec t1, struct timespec t2, struct timespec *td)
{
td->tv_nsec = t2.tv_nsec + t1.tv_nsec;
td->tv_sec = t2.tv_sec + t1.tv_sec;
if (td->tv_nsec >= NS_PER_SECOND)
{
td->tv_nsec -= NS_PER_SECOND;
td->tv_sec++;
}
else if (td->tv_nsec <= -NS_PER_SECOND)
{
td->tv_nsec += NS_PER_SECOND;
td->tv_sec--;
}
}

scn_timespec()

并且“扫描”过程更加困惑(输入通常比输出更困惑):

int scn_timespec(const char *str, struct timespec *value)
{
assert(str != 0 && value != 0);
if (str == 0 || value == 0)
{
errno = EINVAL;
return -1;
}
long sec;
long nsec = 0;
int sign = +1;
char *end;
/* No library routine sets errno to 0 - but this one needs to */
int old_errno = errno;

errno = 0;

/* Skip leading white space */
while (isspace((unsigned char)*str))
str++;

/* Detect optional sign */
if (*str == '+')
str++;
else if (*str == '-')
{
sign = -1;
str++;
}

/* Next character must be a digit */
if (!isdigit((unsigned char)*str))
{
errno = EINVAL;
return -1;
}

/* Convert seconds part of string */
sec = strtol(str, &end, 10);
if (end == str || ((sec == LONG_MAX || sec == LONG_MIN) && errno == ERANGE))
{
errno = EINVAL;
return -1;
}

if (*end != '\0' && !isspace((unsigned char)*end))
{
if (*end++ != '.')
{
errno = EINVAL;
return -1;
}
if (*end == '\0')
nsec = 0;
else if (isdigit((unsigned char)*end))
{
char *frac = end;
nsec = strtol(frac, &end, 10);
if (end == str ||
((nsec == LONG_MAX || nsec == LONG_MIN) && errno == ERANGE) ||
(nsec < 0 || nsec >= NS_PER_SECOND) || (end - frac > 9))
{
errno = EINVAL;
return -1;
}
for (int i = 0; i < 9 - (end - frac); i++)
nsec *= 10;
}
}

/* Allow trailing white space - only */
unsigned char uc;
while ((uc = (unsigned char)*end++) != '\0')
{
if (!isspace(uc))
{
errno = EINVAL;
return -1;
}
}

/* Success! */
value->tv_sec = sec * sign;
value->tv_nsec = nsec * sign;
errno = old_errno;
return 0;
}

关于C、clock_gettime,返回了不正确的纳秒值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46043743/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com