通过父进程的同一Shell上的几个子进程在stdout上写入

时间:2017-04-22 21:38:11

标签: unix process fork stdout read-write

我有一个执行多个forks的进程,生成几个必须在stdout上写入的子进程。因此,不同子流程的消息可能会自行交叉。我该如何避免这个问题?

2 个答案:

答案 0 :(得分:0)

假设您有三个进程,每个进程都尝试输出由四个字符后跟换行符组成的无限系列行:

void four(char c);

int main()
{
    //insert your own error checking
    pid_t p0, p1, p2;
#define PROC(pid,str) pid=fork(); if(0==pid) four(str);
    PROC(p0,'a');
    PROC(p1,'b');
    PROC(p2,'c');

    waitpid(p2, 0,0);
    waitpid(p1, 0,0);
    waitpid(p0, 0,0);

}

如果您的four功能是:

void four(char c)
{
    for(;;){
        for(int i=0; i<4;i++)
            putchar(c);
        putchar('\n');
    }
}

并将程序管道传入此grep调用:

./a.out |grep -v -e aaaa -e bbbb -e cccc

你会得到证明你问题的比赛。

解决这个问题的最简单方法是依靠Linux保证,如果write参数小于管道缓冲区大小,它将不会中断针对管道的write调用(默认为4KiB在我的系统上(您可以从内置的ulimit shell获取大小。)

void four(char c)
{
    for(;;){
        for(int i=0; i<4;i++)
            putchar(c);
        putchar('\n');
        fflush(stdout); 
        //the stdout buffer is surely larger than 5
        //so this is 1 `write`
    }
}

如果您想要更具可移植性和健壮性,可以对共享文件使用锁定:

  void four(char c)
  {
    int fd;
    fd = open("/proc/self/exe", O_RDONLY); 

    for(;;){
        if(0>flock(fd, LOCK_EX))
           perror("flock");

        for(int i=0; i<4;i++)
            { putchar(c); fflush(stdout); }
        putchar('\n'); fflush(stdout);
        //the pipe buf guarantee won't save us here
        //given all these flushes

        //but this lock will
        if(0>flock(fd, LOCK_UN))
           perror("flock");
   }
}

或者,也可以使用fcntl设置文件锁。

答案 1 :(得分:0)

通过“交叉自己”,我认为你的意思是你担心输出是交错的。也就是说,一个进程尝试输出“Hello,World!”,而另一个进程输出“Goodbye,Chicago!”,最终输出为“Hello,Goodby,World!Chicago!”或类似内容。解决此问题的绝对最简单的方法是确保您编写的每条消息都使用单个write系统调用编写,并且数据很小。如果您的消息小于1k(左右,则确切的值取决于系统,通常为4096,很少小于512)。如果使用足够小的缓冲区调用write,则写入将是原子的,不会与任何其他进程的输出交错。如果您的消息不符合您所在系统的大小,则需要使用一些锁定机制。