如何使多个`forked进程使用共享内存进行通信?

时间:2009-02-27 06:25:40

标签: c fork shared-memory

我有一个有5个子进程的父进程。我想向每个子进程发送一个随机变量。每个孩子都会对变量进行平方并将其发送回父母,而父母则将它们汇总在一起。

这甚至可能吗?我无法弄明白......

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

3 个答案:

答案 0 :(得分:6)

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

  • 共享内存。
  • 管道(popen等)。
  • 套接字。

一般来说,在产生孩子之前,我可能会popen在父母的一些通讯会话中;父母将知道所有五个,但每个孩子可以配置为只使用一个。

共享内存也是可能的,虽然你可能每个孩子都必须有几个值来确保通信顺利进行:

  • 存储变量和返回值的值。
  • 存储状态的值(0 =开始,1 =为子项准备好变量,2 =为父项准备好变量)。

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

例如:

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

这给出了一个并行度量,每个孩子不断监视共享内存以进行工作,Main将工作放在那里并定期收到结果。

答案 1 :(得分: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,SPARC上的32位编译):

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()代替{ {1}}似乎也破坏了事情。如果你重视自己的理智,或者如果你想要为你的家庭作业留下任何分数,就不要使用execl()。)

答案 2 :(得分:0)

the anti thread之类的东西可能会让你更容易一些,请参阅示例(特别是ns查找程序)。