gpt4 book ai didi

c - GNU C 使用管道的多进程处理

转载 作者:太空宇宙 更新时间:2023-11-04 08:32:33 25 4
gpt4 key购买 nike

我在大学里学到了在后台处理进程的最简单方法,即使用管道 read 挂起子/父进程 的运行() 函数。老实说,我已经做作业 2 周了,我无法解决异步进程处理。我最小化了我的代码,使用 2 个管道编写单个子进程,并使用 read() 函数阻止父进程和子进程。您可以在下面找到我的代码的当前状态:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char pipeMessage[100];

char* readFromPipe(int pipe)
{
pipeMessage[0] = '\0';
read(pipe, pipeMessage, sizeof(pipeMessage));
fflush(NULL);
return pipeMessage;
}

void writeToPipe(int pipe, char *input)
{
char text[strlen(input) + 1];
strncpy(text, input, (int)strlen(input));
strncat(text, "\0", 1);
printf("TEXT: %s\n", text);
write(pipe, text, sizeof(text));
fflush(NULL);
}

int main(void)
{
int pipes[2][2];
pid_t pid;

if(pipe(pipes[0]) < 0 || pipe(pipes[1]) < 0)
{
printf("[ERROR] create pipes\n");
return -1;
}

printf("[PARENT] Create child1\n");
if((pid = fork()) < 0)
{
printf("[ERROR] Fork error\n");
return -1;
}

if(pid == 0)
{
// Child code
close(pipes[0][0]);
writeToPipe(pipes[0][1], "TEST MESSAGE");
printf("[CHILD1] pipe message: %s\n", readFromPipe(pipes[1][0]));
writeToPipe(pipes[0][1], "-1");
}
else if(pid > 0)
{
// Parent code
close(pipes[0][1]);
close(pipes[1][0]);
char *message;
do
{
message = readFromPipe(pipes[0][0]);
printf("[PARENT] pipe message: %s\n", message);
writeToPipe(pipes[1][1], "-1");
}
while(atoi(message) != -1);
}
return 0;
}

错误如下:

[PARENT] Create child1
TEXT: TEST MESSAGE
[PARENT] pipe message: TEST MESSAGE
TEXT: -1
[CHILD1] pipe message: -1
TEXT: -1�po
[PARENT] pipe message: -1�T MESSAGE
TEXT: -1�po

我尝试用信号实现这个进程处理,但在最终的应用程序中我需要 3 个不同的子进程,异步运行导致信号处理出现问题。我也试图在网上找到一个教程,但每个多处理主题都涵盖了从父到子的简单单消息解决方案,反之亦然。但是我在父进程中需要一个基于字符的菜单,所以 children 应该不断等待父信号/消息,而 parent 也需要等待 child 完成实际任务。请帮助我,因为我真的被困住了。如果您有任何正常的流程处理解决方案,请告诉我,因为我知道这段代码很糟糕。唯一的原因是缺乏正确的教程。提前致谢。

最佳答案

您的编写逻辑有问题,管道布局过于复杂。下面是你的代码,根据我能收集到的最简单的案例进行定制。包含评论以帮助您。我发现在处理链式管道(对于所有意图而言正是它)时最简单的方法是布置一个由展示链接的宏索引的描述符数组:

// some hand macros for access the correct pipes
#define P_READ 0
#define C_WRITE 1
#define C_READ 2
#define P_WRITE 3
#define N_PIPES 4

以上将在最终源列表中。名字对象应该是不言自明的,但如果不是,P_XXX 说明parent 进程使用的管道,C_XXX 说明管道child 进程使用。看到代码时请记住这一点:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>

// some hand macros for access the correct pipes
#define P_READ 0
#define C_WRITE 1
#define C_READ 2
#define P_WRITE 3
#define N_PIPES 4

// reads a buffer up-to len size.
ssize_t readFromPipe(int pipe, char *buff, size_t len)
{
buff[0] = 0;
ssize_t res = read(pipe, buff, len);
assert(res >= 0 && "Failed to read from pipe");
return res;
}

ssize_t writeToPipe(int pipe, const char *input)
{
size_t len = strlen(input)+1;
ssize_t res = write(pipe, input, len);
assert(res == len && "Failed to write to pipe");
return res;
}

int main(void)
{
int pipes[N_PIPES];
char msg[128] = {0};
pid_t pid;

if(pipe(pipes) < 0 || pipe(pipes+2) < 0)
{
printf("[ERROR] create pipes\n");
return EXIT_FAILURE;
}

if((pid = fork()) < 0)
{
printf("[ERROR] Fork error\n");
return EXIT_FAILURE;
}

// parent code
if(pid > 0)
{
// Parent code. close down the child pipes; don't need them
printf("parent(%d) create: child(%d)\n", getpid(), pid);
close(pipes[C_WRITE]);
close(pipes[C_READ]);

do
{
if (readFromPipe(pipes[P_READ], msg, sizeof(msg)) > 0)
{
printf("parent(%d) read : %s\n", getpid(), msg);
writeToPipe(pipes[P_WRITE], "-1");
}
else break;
}
while(atoi(msg) != -1);

// close remaining pipes. no longer needed
close(pipes[P_READ]);
close(pipes[P_WRITE]);
}

else if(pid == 0)
{
// Child code. don't need parent write or child-read lines
close(pipes[P_READ]);
close(pipes[P_WRITE]);

// write message
writeToPipe(pipes[C_WRITE],"test message");

// read test message
if (readFromPipe(pipes[C_READ], msg, sizeof(msg)) > 0)
printf("child(%d) read : %s\n", getpid(), msg);

// write another message
writeToPipe(pipes[C_WRITE], "-1");

// close remaining pipes. no longer needed
close(pipes[C_READ]);
close(pipes[C_WRITE]);
}

return EXIT_SUCCESS;
}

不支持管道描述符数组,其中最大的变化是简化了writeToPipe逻辑,它只是向管道写入一个终止符C字符串,包括终止空字符

ssize_t writeToPipe(int pipe, const char *input)
{
size_t len = strlen(input)+1;
ssize_t res = write(pipe, input, len);
assert(res == len && "Failed to write to pipe");
return res;
}

调用者检查结果以确保它写入了所有请求的数据,并且嵌入式 assert() 宏将在失败时触发调试器。读取功能存在类似的逻辑。

输出(因进程 ID 而异)

parent(2067) create: child(2068)
parent(2067) read : test message
child(2068) read : -1
parent(2067) read : -1

希望对您有所帮助。在处理管道时,特别是在不久的将来您可能会遇到的 stdio 重定向 ( see spoiler here ) 时,为您的代码提供有意义的助记符非常有帮助,例如我在上面使用的宏索引管道数组。

祝你好运。

关于c - GNU C 使用管道的多进程处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27672109/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com