【问题标题】:Why is there an extra percent sign after the output?为什么输出后有一个额外的百分号?
【发布时间】:2018-12-26 13:11:56
【问题描述】:

最近在学习linux下的fork()函数。我写了一个程序。

#include<stdio.h>
int main(){
    int p1, p2;
    while((p1 = fork()) == -1);
    if(p1 == 0)
        printf("b");
    else{
        while((p2 = fork()) == -1);
        if(p2 == 0)
            printf("c");
        else
            printf("a");
    }
}

编译并运行后,我得到了一个意想不到的百分号。

但是如果我在这些字母后面加上\n,百分号就会消失。

有人知道原因吗?

我还有一个问题。每次我重新运行程序时,我都会得到相同的答案。它总是显示“acb”。顺序始终相同。为什么?

【问题讨论】:

  • while((p1 = fork()) == -1); 看起来很像 Android 的 Rage Against the Cage
  • 在C语言中,函数fork()原型通过#include &lt;sys/types.h&gt;#include &lt;unistd.h&gt;这两个头文件的组合可见。如果没有这两个头文件,代码将依赖默认类型(通常是int,但不一定)你的编译器应该已经告诉你这个问题。
  • 关于:while((p1 = fork()) == -1); 最有可能的是,如果fork() 失败,它将继续失败。这不是检查对fork()的调用中的错误的有效/可靠方法@
  • 当一个父进程fork一个子进程时,它应该总是调用wait()waitpid()以便在子进程退出之前它不会退出。

标签: c linux fork


【解决方案1】:

您的 shell (zsh) 添加它以指示输出没有以换行符结尾。

要摆脱它,只需以 \n 结束输出即可。

至于另一个问题,它不是确定性的。如果您在其他地方运行它或运行足够多次,您可能会得到不同的结果。但这说明了为什么很难找到同步问题,因为事情似乎一直(几乎)一直在运行。

【讨论】:

  • 好的,我明白了。谢谢!
  • 注意:(大部分)可预测的排序可能是因为它们在虚拟机中运行(注意提示中的 VirtualBox)。如果虚拟机只模拟一个处理器,那么实际上一次只运行一个进程,并且父级的时间片在fork 之后继续足够长以执行输出是有意义的,所以它总是结束首先输出父级(输出a 的那个)。至于cb 之前,调度程序可能(作为实现细节)倾向于优先考虑最后启动的孩子(导致c 成为下一个输出);这只是一个猜测。
  • 另请注意:如果您想将所有输出放在一行上,您应该让父进程调用wait(2)(2 是手册页部分,而不是参数)两次,然后@ 987654328@ 所以换行符只输出一次,并且只在所有其他输出之后。如果你想保持输出不可预测,你还需要在printf("a");之后但在wait调用之前添加fflush(stdout);,否则当stdout是行或块缓冲时(默认),父进程将总是延迟刷新缓冲区,直到子进程退出,所以a 将最终结束。
【解决方案2】:

以下建议的代码:

  1. 正确检查来自fork()的返回值
  2. 正确包含必要的头文件
  3. 在父进程退出前正确等待子进程退出
  4. 仍然不会用 '\n' 终止输出字符串,因此(在这种情况下)在进程退出之前输出不会显示在终端上。
  5. 对 pid 变量使用正确的类型
  6. 使用main() 的两个有效签名之一

现在建议的代码:

#include <stdio.h>     // printf(), perror()
#include <stdlib.h>    // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <sys/types.h> // pid_t
#include <unistd.h>    // fork()
#include <sys/wait.h>  // wait()

int main( void )
{
    pid_t p1;
    pid_t p2;

    p1 = fork();
    switch( p1 )
    {
        case -1:
            perror( "first fork failed" );
            exit( EXIT_FAILURE );
            break;

        case 0:  // child 1
            printf("child 1");
            exit( EXIT_SUCCESS );
            break;

        default:  // parent
            p2 = fork();
            switch( p2 )
            {
                case -1:
                    perror( "second fork failed" );
                    exit( EXIT_FAILURE );
                    break;

                case 0: // child 2
                    printf("child 2");
                    exit( EXIT_SUCCESS );
                    break;

                default:
                    printf("parent");
                    while( wait( NULL ) != -1 );
                    break;
            }  // end switch 2
    } // end switch 1
}

典型的代码运行结果:

child 2child 1parent

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多