代码之家  ›  专栏  ›  技术社区  ›  Brishna Batool

使用重定向的I/O与子进程通信时出现死锁

  •  0
  • Brishna Batool  · 技术社区  · 7 年前

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

    #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 两者都能正常工作。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Brishna Batool    7 年前

    问题在于 read() write() 处理各种流/文件/管道。我的 写入() 无法与 读取() 它已经写完了。 Read() 依赖于 EOF 只有在管道的写端关闭后才发送。当然,一旦它关闭了,它就永远消失了,我不能再打开它来发送另一个信息。

    因此我改用命名管道( fifo )这样每次写完之后我都可以重新打开管道。