多次分叉后无法将消息发送到父进程
Unable to send message to parent process after multiple forks
我有一个程序,它分叉了四个进程并调用execlp()为孩子运行不同的代码。我给孩子一个数字作为 ID。到目前为止,子进程所做的只是尝试将 id 传递回父进程。如果我在父进程中打印出的流中放置一个字符串,管道就可以工作。但是,当我尝试将 id 作为 int 认为流时,它不起作用。我什至没有进入子命令中的 fprintf() 和 fflush() 命令之后的代码行。
我对创建文件描述符的方式进行了一些更改,并为示例添加了更多代码。现在,在孩子中,我无法创建 FILE*。但是,如果我在文件描述符 1 上创建,它确实会打印到屏幕上。我尝试在文件描述符 3 上创建,程序只是坐在那里等待永远不会来的孩子的输入。
这是我的父母:
Mom::Mom():childCount(0)
{
pipeCount = fileCount = 0;
int fd[2];
srand(time(NULL));
for(int c=0; c<NUMJOBS; ++c) jobs[c] = newJob();
//createFileDescriptors(fd);
ret = pipe(fd);
if(ret < 0) fatal("Error creating pipes");
//cout << fd[0] << "t" << fd[1] << endl;
pipes[fileCount++] = fdopen(fd[0], "r");
fcntl( 3, F_SETFD, 0 );
//close(fd[1]);
//for(int c=3; c<FILEDESCRIPTORS; c+=2) pipes[pipeCount++] = fdopen(c, "w");
createChildren();
for(int c=0; c<4; c++)
{
int tmp = -1;
//cout << "About to read from children, tmp = " << tmp << endl;
ret = fscanf(pipes[0], "%d", &tmp);
//char* buffer = (char*) malloc(80*sizeof(char));
//char buffer[80];
//read(3, buffer, 80);
cout << ret << "t" << tmp << endl;
//cout << ret << " " << tmp << endl;
//free(buffer);
}
//sleep(5);
}
/*------------------------------------------------------------------------------
Create all the children by using fork() and execlp()
----------------------------------------------------------------------------*/
void Mom::createChildren()
{
int fd[2];
fcntl( fd[IN], F_SETFD, 0 );
for(int c=0; c<NUMCHILDREN; c++)
{
ret = pipe(fd);
if(ret < 0) fatal("Error creating pipes");
int pid = fork();
//cout << pid << endl;
if(pid == 0)
{
setupChild(c, fd);
}
else
{
//close(fd[1]);
}
}
}
/*------------------------------------------------------------------------------
set up the child and call exec to run ChildMain
----------------------------------------------------------------------------*/
void Mom::setupChild(int count, int fd[])
{
//cout << "Creating child with id: " << count << endl;
char cnt = '0' + count;
string id_str (&cnt + ' ');
fcntl( fd[0], F_SETFD, 0 );
pipes[fileCount++] = fdopen(fd[1], "w");
//execlp("ChildMain", "ChildMain", id_str.c_str(), NULL);
execlp("ChildMain", id_str.c_str(), NULL);
}
这是子代码:
int main(int argc, char* argv[])
{
//cout << argv[argc-1] << endl;
if(argc < 1) fatal("Not enough arguments provided to ChildMain");
int id = atoi(argv[argc-1]);
//cout << *argv[1] << " " << id << endl;
//redirect STDIN and STDOUT
/*int c_in = dup(0);
close(0);
dup((2*id) + 5);
int c_out = dup(1);
close(1);
dup(4);*/
/////////////////////////////
//Child kid((int) *argv[1]);
FILE* out = fdopen(4, "w");
if(out == NULL)
cout << "Error opening stream to parent in child: " << id << endl;
//char childID = '0' + id;
//char buf[80];
//strcpy(buf, "Child ");
//strcat(buf, &childID);
string buf ("Child");
//cout << tmp << " " << childID << endl;
//write(4, buf.c_str(), buf.length()+1);
//cout << id << endl;
int ret = fprintf(out, "%d", id);
fflush(out);
//fclose(out);
//cout << id << " " << ret << endl;
//ch.push_back((char) id);
//put STDIN and STDOUT back to correct file descriptors
/*close(1);
dup(c_out);
close(0);
dup(c_in);*/
////////////////////////////////////////////////////////
return 0;
}
我很困惑为什么这对第一个孩子有效,id 为 0,但对其他孩子无效。有谁知道我的代码出了什么问题?
execlp(3)
需要以空结尾的字符串,因为它是参数。 &cnt
不会以 null 终止。
简单修复:
void Mom::setupChild(int count, int fd[])
{
char cnt[2];
cnt[0] = '0' + count;
cnt[1] = ' ';
fcntl( fd[(2*count)+3], F_SETFD, 0 );
execlp("ChildMain", "ChildMain", &cnt, NULL);
}
不过,这不会扩展到 10 个进程,所以我可能会使用缓冲区并只在其中 sprintf() 中。
这是一个关于如何实现我评论中的建议的小例子:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
/* Need two sets of pipes: one for child stdin, one for child stdout */
int pipefds1[2];
int pipefds2[2];
pipe(pipefds1);
pipe(pipefds2);
int rc = fork();
if (rc == -1)
perror("fork");
else if (rc == 0)
{
/* In child */
/* Close the old stdin and stdout */
close(STDIN_FILENO);
close(STDOUT_FILENO);
/* Create new stdin/stroud from the pipes */
dup2(pipefds1[0], STDIN_FILENO);
dup2(pipefds2[1], STDOUT_FILENO);
/* Close the unneeded pipe handles */
close(pipefds1[1]);
close(pipefds2[0]);
/* Now pass control to the new program */
execl("/bin/ls", "ls", "-l", "/", NULL);
}
else
{
/* In parent */
/* Close the uneeded pipe handles */
close(pipefds1[0]);
close(pipefds2[1]);
/* We want to use stdio functions */
FILE *fp = fdopen(pipefds2[0], "r");
/* Read all from the child */
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp))
{
printf("Input from child: %sn", buffer);
}
fclose(fp);
/* Wait for child to exit */
wait(NULL);
}
return 0;
}
希望这足以让你继续前进。
错误处理不存在,但经过测试。
相关文章:
- boost::进程间消息队列引发错误
- 避免使用 boost::进程间::消息队列创建文件
- 提升消息队列 跨两个进程未接收
- 使用加速进程间创建消息队列 - 内存访问冲突
- 在两个进程之间传递消息
- boost消息队列线程安全和进程安全吗?
- 服务器进程等待客户端输入/消息的最佳方法是什么?
- C++ - 在进程之间发送消息
- boost::进程间消息队列创建时的竞争条件
- 进程内通信 WinRT(消息替换)
- 如何使用Boost进程间消息队列for Windows
- 连接到子进程stdout的管道中的消息不完整
- 广播消息供所有进程退出 (MPI)
- 使用Windows中另一个进程的事件循环向Qt应用程序发送退出消息
- 这是否可以挂接子进程发送到 Windows 控制台的消息
- 可以放置一个钩子来捕获由子进程发送到控制台的消息
- 多次分叉后无法将消息发送到父进程
- Boost:是否存在用于仅线程通信的进程间消息队列机制
- 带有 epgm 的 ZeroMQ 发布/订阅无法接收由同一主机上的进程发送的消息
- 网络延迟和应用程序>进程消息()