c++ - 与具有重定向 I/O 的子进程通信时出现死锁

标签 c++ linux pipe fork dup2

我正在编写一个程序,以编程方式与 SPIN 模型检查器的交互模块进行通信。为此,我需要重定向 SPIN 的 I/O,从我的程序中启动它,然后重复读取和写入它。为了进行测试,我使用以下只有一个输入和一个输出的短程序而不是自旋:

#include <string> 
#include <iostream> 

using std::cin;
using std::cout;
using std::string;

void sprint(string s);
int main() 
{   
    std::string s = "empty";
    cin >> s;
    cout << "\n\tthe text is: " << s;
    return 0;    
} 

我的程序,主要取自this answer , 是:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <unistd.h>
#include <errno.h>
#include <iostream>

#define PIPE_READ 0
#define PIPE_WRITE 1
#define maxReadSize 2048
using std::cout;
using std::cin;
using std::string;

int createChild(const char* szCommand, const char* aArguments, const char* szMessage);

int main()
{
    createChild("./inout" , "inout", "hello");
    return 0;
}


int createChild(const char* szCommand, const char* aArguments, const char* szMessage) 
{
    int cStdinPipe[2];
    int cStdoutPipe[2];
    int nChild;
    char nChar;
    int nResult;

    if (pipe(cStdinPipe) < 0) 
    { 
        return -1;
    }
    if (pipe(cStdoutPipe) < 0) 
    {
        close(cStdinPipe[PIPE_READ]);
        close(cStdinPipe[PIPE_WRITE]);
        return -1;
    }

    nChild = fork();
    if (0 == nChild) 
    {
        // child continues here
        cout.flush();
        close(cStdinPipe[PIPE_WRITE]);

        // redirect stdin
        if (dup2(cStdinPipe[PIPE_READ], STDIN_FILENO) == -1) 
        {
            exit(errno);
        }

        // redirect stdout
        if (dup2(cStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1) 
        {
            exit(errno);
        }

        // all these are for use by parent only
        close(cStdinPipe[PIPE_READ]);
        close(cStdoutPipe[PIPE_READ]);
        close(cStdoutPipe[PIPE_WRITE]); 

        // run child process image
        nResult = execlp(szCommand, aArguments, NULL);

        // if we get here at all, an error occurred, but we are in the child
        // process, so just exit
        exit(nResult);
    } 
    else if (nChild > 0) 
    {
        // parent continues here
        string messageFromChild = "";
        string messageFromParent = "";
        char readBuffer[maxReadSize];
        int bytesWritten = 0;
        int bytesRead = 0;

        // close unused file descriptors, these are for child only
        close(cStdinPipe[PIPE_READ]);
        close(cStdoutPipe[PIPE_WRITE]); 

        // write to child
        if (NULL != szMessage) 
        {
            bytesWritten = write(cStdinPipe[PIPE_WRITE], szMessage, strlen(szMessage));
        }

        // read from child
        bytesRead = read(cStdoutPipe[PIPE_READ], readBuffer, maxReadSize);

        cout << "\nChild says: " << readBuffer << "\n";

        // done with these in this example program, you would normally keep these
        // open of course as long as you want to talk to the child
        close(cStdinPipe[PIPE_WRITE]);
        close(cStdoutPipe[PIPE_READ]);

        std::cout << "\n\nParent ending";
    } 
    else 
    {
        // failed to create child
        close(cStdinPipe[PIPE_READ]);
        close(cStdinPipe[PIPE_WRITE]);
        close(cStdoutPipe[PIPE_READ]);
        close(cStdoutPipe[PIPE_WRITE]);
    }
    return nChild;
}

运行此程序会导致死锁,子进程卡在 cin 上,而父进程卡在 read() 上。删除这些调用中的任何一个都会导致两个程序运行到终止并正常退出。 write()cout 都可以正常工作。

最佳答案

问题出在 read()write() 如何在各种流/文件/管道上工作。我的 write() 无法与它已完成写入的 read() 通信。 Read() 依赖于 EOF,它仅在管道的写入端关闭后才发送。当然,一旦它关闭,它就永远消失了,我无法重新打开它来发送另一条消息。

因此,我切换到命名管道 (fifo),这样我就可以在每次写入后重新打开管道。

关于c++ - 与具有重定向 I/O 的子进程通信时出现死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51010038/

相关文章:

c - 一个 C 文件在 Linux 中调用并运行另一个 C 文件

C++ 模板用法

c++ - 关于在模板中使用可变参数的逻辑运算符

linux - 如何知道文件是否成功从本地传输到 hdfs

linux - 在 Linux 2.4 上使用 pthread - 出现 "incomplete type"编译错误

node.js - 来自 child_process.exec 的错误 "No such device or address",管道有帮助。为什么?

python - 管道 python3 输出到 dzen2

c++ - 如何更改 Qt 中的工具包以针对 x86 机器?

c++ - SQLite 绑定(bind)参数到通配符

c - C中的多管道bash风格