【问题标题】:printf prints same statement twiceprintf 两次打印相同的语句
【发布时间】:2018-03-14 22:49:12
【问题描述】:

下一个代码应该写入“file.txt”PID 号,父进程为 1,子进程为 0。

我不确定代码是否正常工作,但我遇到了一个奇怪的 Printf() 问题,这会造成麻烦。 我不明白为什么,但是 printf 打印了两次相同的语句。

代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


void print_pids(int fd,int n){
int i,p;
char msg[99];

for(i=n;i>0;i--){
    p=fork();
    if(p>0){
        sprintf(msg,"My generation is 1.My pid is %d\n",getpid());
        write(fd,msg,33);
        wait();
    }
    if(p==0){
        sprintf(msg,"My generation is 0.My pid is %d\n",getpid());
        write(fd,msg,33);
    }
    if(p<0){
        printf("cannot fork");
        exit(0);
    }
}


}

void main(){
    int fd;
    char buf[99];
    fd=open("file.txt",O_WRONLY,700);
    print_pids(fd,1);
    close(fd);
    fd=open("file.txt",O_RDONLY,700);
    read(fd,buf,35);
    printf(" %s\n",buf);
    close(fd);
    return;


}

而不是打印

 My generation is 1.My pid is 8022

打印出来

 My generation is 1.My pid is 8
 My generation is 1.My pid is 8

这是为什么?

谢谢!

【问题讨论】:

  • 子进程没有在print_pids() 中退出,所以它返回到main() 并打开文件,读取它,打印它,然后退出。父母也这样做,但只是在孩子死后。如果您打印了执行打印操作的进程的 PID,您会得到更好的信息。使用带有固定大小缓冲区的write() 也令人担忧。并且没有错误检查。
  • open() 应该使用 0700,而不是 700
  • void main() 应该是 int main(void)。如果你有推荐void main()的C教材,请把它扔到最近的墙上。

标签: c printf fork


【解决方案1】:

子进程没有在print_pids() 中退出,所以它返回到main() 并打开文件,读取它,打印它,然后退出。父母也这样做,但只是在孩子死后。如果您打印了执行打印操作的进程的 PID,您会得到更好的信息。

write() 与固定大小的缓冲区一起使用也令人担忧。并且没有错误检查。

这是您的代码的固定版本 - 更相关的标头,正确调用 wait()(不幸的是您的代码没有崩溃),打印额外的诊断信息,写入消息的完整长度,读取和打印消息的全长(即使没有空终止符),使用八进制数 (0600) 而不是十进制数 (700) 获取权限等。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

static void print_pids(int fd, int n)
{
    int i, p;
    char msg[99];

    for (i = n; i > 0; i--)
    {
        p = fork();
        if (p > 0)
        {
            sprintf(msg, "My generation is 1. My pid is %d\n", getpid());
            write(fd, msg, strlen(msg));
            int status;
            int corpse = wait(&status);
            printf("Child %d exited with status 0x%.4X\n", corpse, status);
        }
        if (p == 0)
        {
            sprintf(msg, "My generation is 0. My pid is %d\n", getpid());
            write(fd, msg, strlen(msg));
        }
        if (p < 0)
        {
            printf("cannot fork");
            exit(0);
        }
    }
}

int main(void)
{
    int fd;
    char buf[99];
    fd = open("file.txt", O_WRONLY|O_CREAT|O_TRUNC, 0600);
    print_pids(fd, 1);
    close(fd);
    fd = open("file.txt", O_RDONLY);
    int nbytes = read(fd, buf, sizeof(buf));
    printf("%.5d: %.*s\n", (int)getpid(), nbytes, buf);
    close(fd);
    return 0;
}

样本输出:

33115: My generation is 1. My pid is 33112
My generation is 0. My pid is 33115

Child 33115 exited with status 0x0000
33112: My generation is 1. My pid is 33112
My generation is 0. My pid is 33115

请注意获取完整的消息长度如何帮助您了解正在发生的事情。您的消息正在截断输出,因此您没有看到完整的 PID。两个进程都写入文件(总共约 72 个字符)。 (可能存在一些时间问题来改变所看到的内容 - 我得到了至少一个异常结果,其中只有一个“我的一代”消息,但我无法可靠地重现。)

【讨论】: