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

时间:2018-02-28 04:48:22

标签: c pipe fork parent-child

我正在分娩一个会运行无限循环并做一些事情的孩子。当孩子处于“准备”状态时,文本将与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\n");
            _exit(1);
        case 0:
            printf("Starting progtest...\n");
            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\n", buffer);

}

子:

#include <stdio.h>

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

    return 0;
}

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

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

1 个答案:

答案 0 :(得分:0)

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

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

协议标题

#include <stdint.h>

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

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

发送消息

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);

阅读邮件

struct Message m;
if (read(fd, &m, sizeof(struct Message)) != sizeof(struct Message))
{
  fprintf(stderr, "Failed to read the header\n");
  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\n");
    exit(1);
  }

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

  offset += r;
}

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

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