我想使用select()实现一个计时器,我希望它在每3秒的间隔后达到超时代码。
如果我删除" timeout.tv_sec + = 8;"从我的代码中等待3秒然后开始打印"超时"连续使用" timeout.tv_sec + = 8"什么都没打印,程序卡住了。什么都没打印出来。有人可以解释一下我在这方面做错了什么吗? 我的代码如下: 基本上,我希望它以3秒的间隔打印超时。
struct timeval timeout;
timeout.tv_sec = 3;
while(1) {
int rc = select(2, NULL, NULL, NULL, &timeout);
if(rc == 0)
{
printf(" time out ");
timeout.tv_sec+=8;
}
if (rc < 0)
{
printf(" Error ");
continue;
}
else
{
printf(" process ");// some instructions
}
}
答案 0 :(得分:3)
您只需重置超时值即可。
在select
返回之前,更新超时值。然后它只包含剩余时间。
如果您根本没有更新,则会出现以下问题:
一旦你的时间用完,你会在以后的每次通话中立即达到超时。
如果使用+=8
进行更新,则会增加剩余超时。如果剩下2.5秒,则会达到10.5秒,依此类推。
为避免这种情况,只需将其再次设置为3秒:
while(1) {
int rc = select(2, NULL, NULL, NULL, &timeout);
timeout.tv_sec = 3;
...
BTW:如果你向select
提供了一些你想要等待的文件描述符,你可能会得到更好的结果。
另一个观察结果:
您未在\n
来电中添加printf
。这不会触发您的stdout
。您可能会打印所有内容,但它不会从缓冲区移动到终端。
答案 1 :(得分:1)
你有两个问题的组合。
select
修改超时结构以指示剩余时间printf
使用缓冲IO。使用printf
编写的文本仍保留在程序的缓冲区中,直到打印\n
或fflush
上调用stdout
或缓冲区已满。如果省略timeout.tv_sec+=8
,则代码等待3秒,然后打印time out
,但它只会进入程序中的内部缓冲区。下一次循环时,超时现在为零,因此程序会立即将time out
打印到缓冲区。对于循环的任何后续执行都是相同的。相当快的缓冲区被填满,程序将其刷新到stdout
,此时您将在屏幕上看到它。
如果您在第一次迭代时离开timeout.tv_sec+=8
select
等待3秒,则在第二次迭代和每次后续迭代中等待8秒。这意味着填充缓冲区需要更长的时间,因此在看到任何输出之前会更长。您打印10 char
s。如果内部缓冲区是4096字节,则打印任何内容大约需要55分钟。
要解决此问题,请在每个打印语句上添加\n
,或定期在fflush
标准输出。
您需要做的另一件事就是每次设置timeout.tv_usec
时将timeout.tv_sec
设置为0。您的代码,因为它保留了struct
未初始化的一半,因此调用未定义的行为。
struct timeval timeout;
while(1) {
timeout.tv_sec = 3 ;
timeout.tv_usec = 0; // Otherwise UB!
int rc = select(2, NULL, NULL, NULL, &timeout);
if(rc == 0)
{
printf(" time out ");
}
if (rc < 0)
{
printf(" Error ");
break; // The error is unlikely to go away next time around
}
else
{
printf(" process ");// some instructions
}
}