Тупик при связи с дочерним процессом с перенаправленным вводом / выводом - PullRequest
0 голосов
/ 24 июня 2018

Я пишу программу для программного взаимодействия с интерактивным модулем проверки модели SPIN. Для этого мне нужно перенаправить ввод-вывод 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;    
} 

Моя программа, взятая в основном из этого ответа , выглядит так:

#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 Ответ

0 голосов
/ 03 июля 2018

Проблема оказалась в том, как read() и write() работают с различными потоками / файлами / каналами. Мой write() не мог сообщить read(), что он закончил писать. Read() полагался на EOF, который был отправлен только после того, как конец записи канала был закрыт. Конечно, как только он был закрыт, он исчез навсегда, и я не мог открыть его, чтобы отправить еще одно сообщение.

Поэтому я переключился на именованные каналы (fifo), чтобы я мог открывать каналы после каждой записи.

...