【问题标题】:Sleep function in C (POSIX) breaks my programC(POSIX)中的睡眠功能破坏了我的程序
【发布时间】:2021-03-23 19:03:20
【问题描述】:

这是我的程序代码:

#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>

void function() {
    srand(time(NULL));
    while(1) {
        int n = rand();
        printf("%d ", n);
        //sleep(1);
    }
}

int main() {
    pid_t pid;

    pid = fork();
    if (pid == 0) {
        function();
    }
}

注释掉 sleep 行(如上面的代码),程序运行良好(即它打印一堆随机数太快,甚至看不到它们是否真的是随机的),但如果我删除注释,程序不会' 不打印任何内容并退出(甚至不是第一次,在它进入睡眠状态之前),即使它编译时没有警告或错误,有或没有注释。

【问题讨论】:

  • 如果您甚至不包含所需的标头,这肯定不会在没有警告的情况下编译。您必须提供minimal reproducible example 才能使您的问题成为主题。作为新用户,也可以使用tour 并阅读How to Ask
  • @UlrichEckhardt 除了标题之外,我认为这是一个很好的初学者问题。
  • @AlbertoPerugini:您实际使用的是什么操作系统? POSIX 是一个复杂的规范(许多操作系统几乎都兼容 POSIX,但并非完全兼容)。例如 DebianMacOSX 几乎符合 POSIX,但在细微的方面有所不同
  • @UlrichEckhardt 我按照建议添加了标题
  • @BasileStarynkevitch 感谢您提供有关 POSIX 的其他信息,我使用的是 Ubuntu,将 fflush 添加到我的代码中修复了它

标签: c fork posix sleep


【解决方案1】:

但如果我删除评论,程序不会打印任何内容并退出

它不会打印,但也不会真正退出。它仍将在后台运行一个进程。这个过程会运行你的无限 while 循环。

p.c 中使用您的代码:

$ gcc p.c 

$ ./a.out 

$ ps -A | grep a.out
 267282 pts/0    00:00:00 a.out

$ killall a.out

$ killall a.out
a.out: no process found

问题是printf 并没有真正打印出来。它只将数据发送到输出缓冲区。为了强制打印输出缓冲区,调用fflush(stdout)

如果你不刷新,那么你只依赖于你正在使用的终端的行为。当您将换行符写入输出流时,终端刷新是很常见的。这就是为什么最好使用printf("data\n") 而不是printf("\ndata") 的原因之一。有关更多信息,请参阅此问题:https://softwareengineering.stackexchange.com/q/381711/283695

我怀疑如果您只是让程序运行,它最终会打印出来。有意义的是,它有一个有限的缓冲区,并且当它满时会刷新。但这只是一个(有根据的)猜测,这取决于您的终端。

它打印一堆随机数的速度太快了,甚至看不出它们是否真的是随机的

你如何判断一个数字序列是否是随机的? (扮演魔鬼代言人)

【讨论】:

    【解决方案2】:

    我相信您需要不时致电fflush(3)。另请参阅 setvbuf(3)stdio(3)sysconf(3)

    我猜如果你编码:

    while(1) {
        int n = rand();
        printf("%d ", n);
        if (n % 4 == 0)
           fflush(NULL);
        sleep(1);
    }
    

    您的程序的行为可能对用户更加友好。 stdout 的缓冲区可能至少有几十千字节。

    顺便说一句,我可能是错的。通过阅读最近的 C 草案标准(可能是 n2176)来检查。

    至少,请访问this C reference 网站,然后查看syscalls(2)fork(2)sleep(3)

    您需要为每个成功的fork(2) 调用waitpid(2) 或类似的函数。

    如果在 Linux 上,另请阅读 Advanced Linux Programming 并同时使用 strace(1)gdb(1) 来了解程序的行为。使用 GCC 不要忘记将其编译为 gcc -Wall -Wextra -g 以获取所有警告和调试信息。

    考虑也使用Clang static analyzer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-16
      • 2012-01-12
      • 2011-06-23
      • 2011-03-23
      • 2021-02-07
      • 2011-02-03
      • 1970-01-01
      相关资源
      最近更新 更多