【发布时间】:2010-10-10 06:33:10
【问题描述】:
我有一个有 5 个子进程的父进程。我想向每个子进程发送一个随机变量。每个孩子都会对变量进行平方并将其发送回父级,然后父级会将它们全部相加。
这甚至可能吗?我想不通...
编辑:此进程将使用共享内存。
【问题讨论】:
标签: c fork shared-memory
我有一个有 5 个子进程的父进程。我想向每个子进程发送一个随机变量。每个孩子都会对变量进行平方并将其发送回父级,然后父级会将它们全部相加。
这甚至可能吗?我想不通...
编辑:此进程将使用共享内存。
【问题讨论】:
标签: c fork shared-memory
有很多方法可以做到这一点,都涉及某种形式的进程间通信。您选择哪一个将取决于许多因素,但其中一些是:
popen 等)。一般来说,我可能会popen 在生成子代之前在父代中进行一些通信会话;父母会知道所有五个,但每个孩子可以配置为只使用一个。
共享内存也是一种可能,尽管您可能必须为每个孩子设置几个值以确保通信顺利进行:
在所有情况下,您都需要一种方法让孩子们只接受他们的价值观,而不是那些注定要给其他孩子的价值观。这可能就像向共享内存块添加一个值以存储孩子的 PID 一样简单。所有子节点都会扫描块中的每个元素,但只会处理状态为 1 且 PID 为其 PID 的元素。
例如:
这给出了并行度的度量,每个子进程持续监控共享内存的工作,Main 将工作放在那里并定期接收结果。
【讨论】:
最讨厌的方法是使用vfork(),让不同的孩子在退出之前踩踏内存的不同部分;然后父级只是将修改后的内存位相加。
非常不推荐 - 但这是我遇到的唯一一个 vfork() 可能真正有用的案例。
只是为了娱乐(我的)我把这个编码了:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/wait.h>
int main(void)
{
int i;
int array[5];
int square[5];
long sum = 0;
srand(time(0));
for (i = 0; i < 5; i++)
{
array[i] = rand();
if (vfork() == 0)
{
square[i] = array[i] * array[i];
execl("/bin/true", "/bin/true", (char *)0);
}
else
wait(0);
}
for (i = 0; i < 5; i++)
{
printf("in: %d; square: %d\n", array[i], square[i]);
sum += square[i];
}
printf("Sum: %d\n", sum);
return(0);
}
这行得通。以前使用“exit(0)”代替“execl()”的试用版不起作用;方阵全为零。示例输出(Solaris 10 上的 32 位编译,SPARC):
in: 22209; square: 493239681
in: 27082; square: 733434724
in: 2558; square: 6543364
in: 17465; square: 305026225
in: 6610; square: 43692100
Sum: 1581936094
有时,总和会溢出 - 在处理上还有很大的改进空间。
“vfork()”的 Solaris 手册页说:
与 fork() 函数不同,子进程借用 父级的内存和控制线程,直到调用 execve() 或退出(异常或通过调用 _exit()(参见 exit(2))。在此期间所做的任何修改 时间到子进程中内存的任何部分都反映 在从 vfork() 返回的父进程中。父母 进程在子进程使用其资源时暂停。
这可能意味着我的代码中不需要“wait()”。 (但是,尝试简化代码似乎使其行为不确定。i 不会过早更改是相当重要的;wait() 确实确保了同步性。使用_exit() 而不是execl() 似乎也中断了不要使用vfork(),如果你重视自己的理智——或者如果你想为你的家庭作业打分。)
【讨论】:
pid_t pid。在 Mac OS X 上,我也得到不正确的结果。它打印了 2 个输出块,其中一些方块显然是错误的。在第二个输出块之后,该进程被挂起(但没有循环)。虽然没有尝试调试它。
the anti thread 之类的内容可能会让您更轻松一些,请参阅示例(尤其是 ns 查找程序)。
【讨论】: