【问题标题】:Synchronizing pipe access for two way read/write同步管道访问以进行双向读/写
【发布时间】:2017-03-20 15:30:10
【问题描述】:

我有一段遗留代码,我在其中将某些逻辑委派给子进程。要求是父级写入管道,子级读取管道。读完后,子进程向新管道写入内容,父进程从中读取。

在下面的代码中,函数 send() 由父进程中的专用线程定期调用。

LaunchWorker() 确保子进程仅在第一次调用时被派生。

1) 我无法弄清楚如何关闭两个描述符的读写端,以便在每次写入时刷新写入管道的旧数据。 2) 两个描述符还需要调用 pipe() 两次吗?

任何使此代码工作的输入将不胜感激。 谢谢!

typedef struct
{
    WebClient* wc; // user defined class
    string url;
    string data;
    size_t dataLen;
    DownloadObserver* downloadCallback; // user defined class
    string* token;
}Payload;

PayLoad pl;

static pid_t worker_pid = 0;
int fd1[2];
int fd2[2];

bool done = false;

void LaunchWorker()
{
    if (worker_pid != 0)
    {
        return;
    }
    pipe(fd1);
    pipe(fd2);

    worker_pid = fork();

}

void send()
{
    //populate pl;

    LaunchWorker();

    if (worker_pid == 0)
    {
        while(true)
        {
            close(fd1[1]);
            close(fd2[0]);

            int cr = read(fd1[0], &pl, sizeof(Payload));
            if (cr > 0)
            {
                // Upload some data to a remote http endpoint - uses libcurl
                //if upload success, done = true

                int cw = write(fd2[1], &done, sizeof(bool));
                if (cw > 0)
                {
                    // success
                }
                else
                {
                    // failure
                }
            }
            else
            {
                // failure
            }
        }
    }
    else if (workper_pid > 0)
    {
        close(fd1[0]);
        close(fd2[1]);
        int pw = write(fd1[1], &pl, sizeof(Payload));
        if (pw > 0)
        {
            int pr = read(fd2[0], &done, sizeof(bool));
            if (pr > 0) 
            {
                // do something with value read
            }
            else
            {
                // failure
            }
        }
        else
        {
            failure
        }
    }
}

【问题讨论】:

  • 是的,您需要调用pipe 两次,以创建两个管道。这是因为管道是单向的,它们只是单向的。
  • 谢谢。关于我的第一个问题,关于我应该在代码中调用 close() 的顺序的任何提示?
  • 您应该关闭每个进程中不使用的描述符(例如,子进程中的fd1[1])。除此之外,您不需要关闭任何管道描述符。我不确定你需要什么样的“同步”?您是否正在发送大量数据? Payload 的大小是多少?
  • 谢谢。我已经使用 Payload 结构定义编辑了代码,并添加了对 close() 的调用。 sizeof(Payload) 为 80。另请参阅下面我对 JeremyP 对我所看到的问题的回答的评论。我完全迷失了为什么第二次阅读不起作用。
  • 一个可能的问题是您在进程之间传输指针。一旦进程与fork 调用分开,它们就会有不同的内存映射。指向fork 之后分配的一些内存的指针在其他进程中将无效。

标签: c linux embedded-linux


【解决方案1】:

首先,你需要在fork之后立即关闭管道的未使用端,因此父级应关闭fd1的读取端和fd2的写入端,子级应关闭写入fd1 的结束和 fd2 的读取结束。如果不这样做,完成后管道将不会关闭。

然后,当您想停止一切时,我会让每个管道的写入器关闭管道的写入端。即

  • 父级关闭 fd1 的写入端
  • child 读取 fd1 上的 eof 并关闭它
  • child关闭fd2的写端
  • parent 读取 fd2 上的 eof 并关闭它。

如果孩子主动关闭,则反之亦然。

最后,父进程应该发出wait系统调用来收集子进程的退出结果。

是的,您确实需要两个管道。管道是一种方式。

【讨论】:

  • 谢谢。我已经编辑了上面的代码以显示至少 1) 在两个进程中关闭不需要的描述符 2) Payload 结构的定义。我目前看到的问题是,在第一次写入/读取时,一切正常。第二个写的也不错。 pl 具有预期值。然而,在第二次阅读之后,当我检查 pl 时,我仍然在 pl.url 中看到相同的值。第二次(及后续)读取可能出现什么问题? sizeof(Payload) 80 字节。
  • 就在 child 的 read() 之前,我还为 pl 分配了内存。 '有效负载* pl = (有效负载*)malloc(sizeof(有效负载));'第二次读取的大小也是正确的 - 80 字节。但我仍然无法让第二次阅读工作。与上述相同的问题。
  • @user2930006 而不是编辑这个问题来改变它,你应该创建一个新问题
猜你喜欢
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
相关资源
最近更新 更多