在无限循环中从子进行read()stdout

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在无限循环中从子进行read()stdout相关的知识,希望对你有一定的参考价值。

我要求一个孩子,这个孩子将运行一个无限循环并做一些事情。当孩子处于“准备”状态时,文本将与printf一起打印到stdout。我用管道重定向孩子的标准输出,以便父母可以看到它。打印此文本时,我希望取消阻止父级。

问题似乎是即使在printf()调用之后read()调用仍将保持阻塞状态。

以下是我正在使用的一些示例代码:

父:

#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd[2];
    pipe(fd);
    char buffer[256];

    switch(fork())
    {
        case -1:
            printf("fork failed
");
            _exit(1);
        case 0:
            printf("Starting progtest...
");
            close(fd[0]);
            dup2(fd[1], STDOUT_FILENO);
            close(fd[1]);
            execl("progtest", "progtest", NULL);

            perror("exec failed");
            _exit(1);
    }

    close(fd[1]);
    read(fd[0], &buffer, sizeof(buffer));
    close(fd[0]);

    printf("buffer: %s
", buffer);

}

儿童:

#include <stdio.h>

int main()
{
    printf("ready
");
    while(1)
    {
        // stuff happens here
    }

    return 0;
}

我很确定管道设置正确。如果我删除无限循环,父将解除阻止并打印“就绪”。

当孩子还在跑步时,有什么方法可以使用read()吗?我是否通过使用管道错误地解决了这个问题?我需要两次使用两个不同的状态消息执行此操作。

答案

您似乎正在尝试执行进程间通信(IPC)。没有1到1的通信同步与读/写,父或子可以一次写入文件描述符,因为它们是异步运行,你必须确保你已经准备好处理这个。

通常,这是通过发送包含有效负载长度的固定大小的每条消息的标头来完成的。例如:

protocol header

#include <stdint.h>

struct Message
{
  uint8_t length; // assuming a maximum message length of 255 bytes, adjust as needed.
};

你可以在这里定义额外的东西,通常最好包括版本,也许是序列ID等。重要的是,如果你通过网络进行通信,这个头的大小在所有硬件实现上是绝对的,所以使用需要stdint定义来确保体系结构之间的兼容性。如果跨架构工作,确保endian是一致的也是一个好主意。

sending a message

const char data[] = "example";

// create a buffer large enough to pack the header and data into it
const uint8_t len = strlen(data) + 1;
char buffer[sizeof(struct Message) + len];

// populate the header
struct Message *m = (struct Message *)buffer;
m->length = len;

// copy in the payload after the header
memcpy(buffer + sizeof(struct Message), data, len);

// write the packed buffer
write(fd, buffer, sizeof(struct Message) + len);

reading a message

struct Message m;
if (read(fd, &m, sizeof(struct Message)) != sizeof(struct Message))
{
  fprintf(stderr, "Failed to read the header
");
  exit(1);
}

// If required perform validation on the header here

ssize_t offset = 0;
char data[m.length];
while(offset < m.length)
{
  ssize_t r = read(fd, data + offset, m.length - offset);
  if (r < 0)
  {
    fprintf(stderr, "Read of message body failed
");
    exit(1);
  }

  if (r == 0)
  {
    fprintf(stderr, "The sender closed the connection
");
    exit(1);
  }

  offset += r;
}

printf("Message Length: %u, Message Data: %s
", m.length, data);

要读取的while循环是必需的,因为如果发送方超过写缓冲区并且现在阻止等待写入余数,则数据可能已被拆分为块。标题也可以在块之间拆分,理想情况下也应该使用相同的技术读取,但为了简洁起见,我将其排除在外。

以上是关于在无限循环中从子进行read()stdout的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio::async_read 无限循环,接收数据为零字节

Python分别从子进程stdout和stderr读取,同时保留顺序

我的代码中某处的无限循环

javascript制作图javascript制作图片无限懒加载,轻松又实用片无限懒加载,轻松又实用

为啥for循环在c中无限进行

使用 socketpair 进行双向通信:挂起子进程的读取输出