kylex
kylex

Reputation: 14406

How to make multiple `fork()`-ed processes comunicate using shared memory?

I have a parent with 5 child processes. I'm wanting to send a random variable to each child process. Each child will square the variable and send it back to the parent and the parent will sum them all together.

Is this even possible? I can't figure it out...

edit: this process would use shared memory.

Upvotes: 3

Views: 3495

Answers (3)

paxdiablo
paxdiablo

Reputation: 881363

There are a great number of ways to do this, all involving some form of inter-process communication. Which one you choose will depend on many factors, but some are:

  • shared memory.
  • pipes (popen and such).
  • sockets.

In general, I would probably popen a number of communications sessions in the parent before spawning the children; the parent will know about all five but each child can be configured to use only one.

Shared memory is also a possibility, although you'd probably have to have a couple of values in it per child to ensure communications went smoothly:

  • a value to store the variable and return value.
  • a value to store the state (0 = start, 1 = variable ready for child, 2 = variable ready for parent again).

In all cases, you need a way for the children to only pick up their values, not those destined for other children. That may be as simple as adding a value to the shared memory block to store the PID of the child. All children would scan every element in the block but would only process those where the state is 1 and the PID is their PID.

For example:

  • Main creates shared memory for five children. Each element has state, PID and value.
  • Main sets all states to "start".
  • Main starts five children who all attach to the shared memory.
  • Main stores all their PIDs.
  • All children start scanning the shared memory for state = "ready for child" and their PID.
  • Main puts in first element (state = "ready for child", PID = pid1, value = 7).
  • Main puts in second element (state = "ready for child", PID = pid5, value = 9).
  • Child pid1 picks up first element, changes value to 49, sets state to "ready for parent"), goes back to monitoring.
  • Child pid5 picks up second element, changes value to 81, sets state to "ready for parent"), goes back to monitoring.
  • Main picks up pid5's response, sets that state back to "start.
  • Main picks up pid1's response, sets that state back to "start.

This gives a measure of parallelism with each child continuously monitoring the shared memory for work it's meant to do, Main places the work there and periodically receives the results.

Upvotes: 6

user50049
user50049

Reputation:

Things like the anti thread might make this a little easier for you, see the examples (in particular the ns lookup program).

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753675

The nastiest method uses vfork() and lets the different children trample on different parts of memory before exiting; the parent then just adds up the modified bits of memory.

Highly unrecommended - but about the only case I've come across where vfork() might actually have a use.

Just for amusement (mine) I coded this up:

#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);
}

This works. The previous trial version using 'exit(0)' in place of 'execl()' did not work; the square array was all zeroes. Example output (32-bit compilation on Solaris 10, SPARC):

in: 22209; square: 493239681
in: 27082; square: 733434724
in: 2558; square: 6543364
in: 17465; square: 305026225
in: 6610; square: 43692100
Sum: 1581936094

Sometimes, the sum overflows - there is much room for improvement in the handling of that.

The Solaris manual page for 'vfork()' says:

Unlike with the fork() function, the child process borrows the parent's memory and thread of control until a call to execve() or an exit (either abnormally or by a call to _exit() (see exit(2)). Any modification made during this time to any part of memory in the child process is reflected in the parent process on return from vfork(). The parent process is suspended while the child is using its resources.

That probably means the 'wait()' is unnecessary in my code. (However, trying to simplify the code seemed to make it behave indeterminately. It is rather crucial that i does not change prematurely; the wait() does ensure that synchronicity. Using _exit() instead of execl() also seemed to break things. Don't use vfork() if you value your sanity - or if you want any marks for your homework.)

Upvotes: 3

Related Questions