3

我有一个有 5 个子进程的父进程。我想向每个子进程发送一个随机变量。每个孩子将平方变量并将其发送回父母,父母将把它们加在一起。

这甚至可能吗?我想不通...

编辑:此过程将使用共享内存。

4

3 回答 3

6

有很多方法可以做到这一点,都涉及某种形式的进程间通信。您选择哪一个将取决于许多因素,但其中一些是:

  • 共享内存。
  • 管道(popen等)。
  • 插座。

一般来说,popen在产生孩子之前,我可能会在父母中进行多次交流;父母会知道所有五个,但每个孩子可以配置为只使用一个。

共享内存也是一种可能性,尽管您可能必须在每个孩子中有几个值以确保通信顺利进行:

  • 一个值来存储变量和返回值。
  • 存储状态的值(0 = 开始,1 = 变量为子准备就绪,2 = 变量再次为父准备就绪)。

在所有情况下,您都需要一种方法让孩子们只接受他们的价值观,而不是那些注定要给其他孩子的价值观。这可能就像向共享内存块添加一个值来存储孩子的 PID 一样简单。所有子节点都会扫描块中的每个元素,但只会处理状态为 1 且 PID 是其 PID 的元素。

例如:

  • Main 为五个孩子创建共享内存。每个元素都有状态、PID 和值。
  • Main 将所有状态设置为“开始”。
  • Main 启动五个孩子,他们都附加到共享内存。
  • 主要存储他们所有的 PID。
  • 所有孩子都开始扫描共享内存的 state = "ready for child" 和他们的 PID。
  • 主要放入第一个元素(状态=“准备好孩子”,PID = pid1,值= 7)。
  • 主要放入第二个元素(状态=“准备好孩子”,PID = pid5,值= 9)。
  • 子 pid1 拾取第一个元素,将值更改为 49,将状态设置为“准备好为父”),返回监控。
  • 子 pid5 拾取第二个元素,将值更改为 81,将状态设置为“为父级准备就绪”),返回监控。
  • Main 获取 pid5 的响应,将该状态设置回“start.
  • Main 获取 pid1 的响应,将该状态设置回“开始。

这给出了并行度的度量,每个子进程持续监控共享内存的工作,Main 将工作放在那里并定期接收结果。

于 2009-02-27T06:28:57.740 回答
3

最讨厌的方法是使用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

有时,总和会溢出——在处理上还有很大的改进空间。

' ' 的 Solaris 手册页vfork()说:

与 fork() 函数不同,子进程借用父进程的内存和控制线程,直到调用 execve() 或退出(异常或调用 _exit() (参见 exit(2))。任何修改在此期间对子进程内存的任何部分进行的操作都会在从 vfork() 返回时反映在父进程中。父进程在子进程使用其资源时暂停。

这可能意味着 ' wait()' 在我的代码中是不必要的。(然而,试图简化代码似乎使它的行为不确定。它i不会过早改变是相当重要的;wait()确实确保同步性。使用_exit()而不是似乎也破坏了事情。如果你重视你的理智,请execl()不要使用-vfork()或者如果你想为你的家庭作业打分。)

于 2009-02-27T06:43:05.100 回答
0

诸如反线程之类的东西可能会让您更容易,请参阅示例(特别是 ns 查找程序)。

于 2009-02-27T07:57:39.180 回答