c/c++语言开发共享关于fork和printf / write


可能重复:
fork()和输出

通过运行:

#include int main() { fork(); printf("b"); if (fork() == 0) { write(1, "a", 1); }else{ write(1, "c", 1); } return 0; } 

我有cbcabbab ,有人可以向我解释输出吗? 如果可能的话,是否有工具可以逐步查看运行程序?

    尝试再次运行它,你可能会获得不同的输出。

    至于一步一步查看过程的工具,我认为strace -f可能会有所帮助:

     $ strace -f ./weirdfork execve("./weirdfork", ["./weirdfork"], [/* 35 vars */]) = 0 ... uninteresting boiler plate removed ... clone(Process 8581 attached child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8581 [pid 8580] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [pid 8581] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [pid 8580] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0  [pid 8581] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0  [pid 8580] <... mmap resumed> ) = 0x7fe1c7d22000 [pid 8581] <... mmap resumed> ) = 0x7fe1c7d22000 [pid 8581] clone(  [pid 8580] clone(Process 8582 attached  [pid 8581] <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8582 Process 8583 attached [pid 8580] <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8583 [pid 8580] write(1, "c", 1  [pid 8581] write(1, "c", 1cc) = 1 [pid 8580] <... write resumed> ) = 1 [pid 8581] write(1, "b", 1b  [pid 8580] write(1, "b", 1  [pid 8581] <... write resumed> ) = 1 b[pid 8581] exit_group(0) = ? Process 8581 detached [pid 8580] <... write resumed> ) = 1 [pid 8580] exit_group(0) = ? [pid 8583] write(1, "a", 1  [pid 8582] write(1, "a", 1a) = 1 a[pid 8582] write(1, "b", 1  [pid 8583] <... write resumed> ) = 1 [pid 8583] write(1, "b", 1b) = 1 [pid 8583] exit_group(0) = ? Process 8583 detached b<... write resumed> ) = 1 exit_group(0) = ? Process 8582 detached 

    简短回答:不要混用缓冲和无缓冲的代码。

    答案很简单:让我们使用以下命令测试源代码的变体:

     $ rm dump $ for X in 0 1 2 3 4 5 6 7 8 9; do for Y in 0 1 2 3 4 5 6 7 8 9; do for Z in 0 1 2 3 4 5 6 7 8 9; do echo `./program` >> dump; done; done; done $ sort -u dump 

    这会执行program一千次,并列出它返回的所有唯一输出。

    缓冲版本:用fwrite (或printf )替换write

     #include  #include  int main() { fork(); printf("b"); if (fork() == 0) { fwrite("a", 1, 1, stdout); }else{ fwrite("c", 1, 1, stdout); } return 0; } 

    这给出了非常规则的输出模式。 实际上,只有六种输出是可能的:

     bababcbc babcbabc babcbcba bcbababc bcbabcba bcbcbaba 

    到底是怎么回事?

    无缓冲版本:通过write替换printf

     #include  int main() { fork(); write(1, "b", 1); if (fork() == 0) { write(1, "a", 1); }else{ write(1, "c", 1); } return 0; } 

    现在可能的输出变化多了,但考虑到并发性,它仍然是可以理解的:

     bbacca bbcaac bbcaca bbccaa bcabca bcbaca 

    这可能是您期望的输出。

    混合版(你的)

    您的代码比前两个变体提供了更多的结果:

     cabbacbb cabbcabb cabbcbab cabcabbb cabcbabb cabcbbab ... etc ... 

    这是因为write调用会立即产生输出,但缓冲的"b"只会在每个进程终止时打印,当然也就是 write调用之后 。 就像在完全缓冲版本中一样,每个进程在stdout缓冲区中都会有"b" ,所以你最终会看到其中的四个。

    除非您专门添加代码来同步分叉进程,否则它们将完全独立运行,因此输出顺序完全是“随机”的。 进程调度将决定接下来要运行的是谁,这又取决于系统中有多少处理器核,运​​行的是什么,以及当前运行的每个进程运行了多长时间。

    如链接中所述,您还可以从printf的内部缓冲区获得输出,因为输出尚未写入表示stdout的实际文件中 – 您可以通过添加fflush(stdout);来“修复”该fflush(stdout);printf之后。

      以上就是c/c++开发分享关于fork和printf / write相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/522010.html

      (0)
      上一篇 2020年12月9日
      下一篇 2020年12月9日

      精彩推荐