Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 死锁linux管道_C_Linux_Unix_Linux Kernel_Pipe - Fatal编程技术网

C 死锁linux管道

C 死锁linux管道,c,linux,unix,linux-kernel,pipe,C,Linux,Unix,Linux Kernel,Pipe,我想学习Linux管道是如何工作的!我编写了一个简单的小程序,它使用管道在父进程和子进程之间传递字符串。然而,这个程序导致了一个死锁,我不知道它的原因是什么 代码如下: #include <sys/wait.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define

我想学习Linux管道是如何工作的!我编写了一个简单的小程序,它使用管道在父进程和子进程之间传递字符串。然而,这个程序导致了一个死锁,我不知道它的原因是什么

代码如下:

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

#define SIZE 100  

int
main(int argc, char *argv[])
{
    int pfd[2];
    int read_pipe=0, write_pipe=0; 
    pid_t cpid;
    char buf[SIZE]; 

    /* PIPE ***************************************
     * pipe() creates a pair of file descriptors, *
     * pointing to a pipe inode, and places them  *
     * in the array pointed to by filedes.    *
     * filedes[0] is for reading,         *
     * filedes[1] is for writing          *
     **********************************************/

    if (pipe(pfd) == -1) { 
        perror("pipe"); 
        exit(EXIT_FAILURE);
    }

    read_pipe=pfd[0]; 
    write_pipe=pfd[1]; 

    cpid = fork();
    if (cpid == -1) { 
        perror("fork"); 
        exit(EXIT_FAILURE);
    }


    if (cpid == 0) {    /* Child reads from pipe */

    char * hello = "I am a child process\n"; 
    sleep(1);  
    // wait until there is some data in the pipe
        while (read(read_pipe, buf, SIZE) > 0);
    printf("Parent process has written : %s\n", buf);
    write(write_pipe, hello, strlen(hello)); 
    close(write_pipe);
    close(read_pipe);
        _exit(EXIT_SUCCESS);
    } else {                /* Parent writes argv[1] to pipe */

    char * hello = "I am a parent process\n";
    write(write_pipe, hello, strlen(hello));
    while (read(read_pipe, buf, SIZE) > 0); 
printf("Child process has written : %s\n", buf);

    close(write_pipe);       
    close(read_pipe);

    wait(NULL);             /* Wait for child */
    exit(EXIT_SUCCESS);
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#定义大小100
int
main(int argc,char*argv[])
{
int-pfd[2];
int read_pipe=0,write_pipe=0;
pid_t cpid;
字符buf[大小];
/*烟斗***************************************
*pipe()创建一对文件描述符*
*指向管道索引节点,并放置它们*
*在filedes指向的数组中*
*filedes[0]用于读取*
*filedes[1]用于写入*
**********************************************/
如果(管道(pfd)=-1{
佩罗(“管道”);
退出(退出失败);
}
read_pipe=pfd[0];
写入管道=pfd[1];
cpid=fork();
如果(cpid==-1){
佩罗尔(“福克”);
退出(退出失败);
}
如果(cpid==0){/*子级从管道读取*/
char*hello=“我是一个子进程\n”;
睡眠(1);
//等待,直到管道中有一些数据
而(读取(读取管道、buf、尺寸)>0);
printf(“父进程已写入:%s\n”,buf);
写信(写信,你好,斯特伦(你好));
关闭(写入管道);
关闭(读取管道);
_退出(退出成功);
}else{/*父对象将argv[1]写入管道*/
char*hello=“我是父进程\n”;
写信(写信,你好,斯特伦(你好));
而(读取(读取管道、buf、尺寸)>0);
printf(“子进程已写入:%s\n”,buf);
关闭(写入管道);
关闭(读取管道);
等待(NULL);/*等待子项*/
退出(退出成功);
}
}
在这篇文章中,您可以找到父级和子级之间管道的正确操作。您这里的问题是通信设置不正确

管道应仅用于在一个方向上通信,因此一个进程必须关闭读描述符,另一个进程必须关闭写描述符。否则,将发生的情况是,对“read”(父进程和子进程)的调用,因为它可以检测到管道上存在另一个具有打开写入描述符的进程,当它发现管道为空时(不返回0),将阻塞,直到有人在其中写入内容。所以,你父亲和你儿子的阅读都被阻止了

有两种解决方案:

。创建两个管道,每个方向一个用于通信,并按照上面链接中的说明执行初始化。在这里,您必须记住在发送完消息后关闭写描述符,这样其他进程的读取将返回,或者将循环设置为读取的字节数(而不是读取的返回),这样在读取整个消息时就不会执行另一个调用。例如:

int bread = 0;
while(bread < desired_count)
{
   bread += read(read_pipe, buf + bread, SIZE - bread);
}
int-bread=0;
while(面包<所需数量)
{
面包+=读取(读取管道,buf+面包,尺寸-面包);
}

。您可以像以前一样创建一个管道,并修改读取描述符上的标志,使用也可以有O_NONBLOCK,这样当管道中没有信息时,对读取的调用就不会被阻塞。在这里,您需要检查read的返回值,以知道您收到了什么,然后进行累加,直到得到消息的完整长度。此外,您还必须找到一种方法来同步这两个进程,以便它们不会读取不适合它们的消息。我不建议您使用此选项,但如果您想使用条件变量,可以尝试使用它。

也许您可以知道是否看到任何printf()输出? 无论如何,如果您想在您的家长和孩子之间建立双向通信,您应该使用两个管道,一个用于从家长到孩子写入数据,另一个用于从孩子到家长写入数据。此外,您的读取循环可能是危险的:如果数据分为两个或更多块,则第二个read()将覆盖第一部分(我从未见过这种情况发生在本地管道上,但例如套接字)。当然,在read()之后,yout不会自动以null结尾,因此仅使用“%s”打印int也可能会导致问题。 我希望这能给你一些尝试的想法