Q:

Problema con procesos y reserva de memoria

Tengo el siguiente ejercicio:
Realice un programa que expanda N procesos hijos. Cada hijo debe compartir
una variable denominada contador, que debe estar inicializada a cero. Esta variable debe ser incrementada por cada hilo 100 veces. Imprima la variable una vez finalicen los hilos y analice el resultado obtenido. Un resultado previsible para 3 procesos sería 300.
Tengo el siguiente codigo pero no consigo que me realize correctamente la suma, creo que el problema esta en la reserva de memoria.
#define CHILDREN    3
#define OK  7

int suma;

void adder(int);

int main()
{

    int i,j, shmid, status;
    key_t key;

    extern int suma ;
    struct shmid_ds buf;

   //  Shared memory
    key = ftok("adicional2.c", 1);
    if ((shmid = shmget(key, sizeof(int), IPC_CREAT | 0777)) == -1){

    exit(1);
    }
        suma=(int) shmat(shmid,NULL,0);
        suma=0;

    // creacion hilos
    for (i = 0; i < CHILDREN; i++) {

    pid_t pid = fork();
    if (pid==0) {//cuando fork es igual de 0

        adder(i);
        printf("%d",suma);

        exit(0);
    }

    }

    // Wait to finish
    for (i = 0; i < CHILDREN; i++) {
    pid_t pid = wait(&status);

    printf("\nHijo %d ha terminado status %d\n", pid, WEXITSTATUS(status));
    }

   // Final result
  printf("\nSuma");

    printf("[%d]",suma);

printf("\n");

}

void adder(int id)
{

int i,shmid;

extern int suma ;

    key_t key;
   //  Shared memory
    key = ftok("adicional2.c", 1);
    if ((shmid = shmget(key, sizeof(int), IPC_CREAT | 0777)) == -1)

        perror("Child");

//Creacion de hilos

            if(id==0){//proceso 1 fila 1
                suma+=100;
                printf("suma hijo 1= %d",suma);
                exit(OK);
            }

            if(id==1){//proceso 2 fila 2{

                suma+=100;
                printf("suma hijo 2=%d",suma);
                exit(OK);
            }
            if(id==2){  //proceso 3 fila 3{

                suma+=100;
                printf("suma hijo 3=%d",suma);
                exit(OK);           
            }

}

Como digo creo que el fallo es de la reserva de memoria, ya que cada hijo me devuelve 100 pero no lo suma con el anterior.

A:

Tienes varios fallos:

No necesitas ninguna variable global en tu programa. Tanto main() como adder() (y por tanto cada uno de los hijos) tienen su propia variable suma.
Ahora bien, esas variables no son de tipo int, sino puntero a int y lo que hay que hacer para que compartan el dato es hacer que todas ellas apunten a una misma dirección de memoria física.
Ya que cada proceso tiene su propio espacio de direcciones virtuales, es imposible hacer que un puntero en un proceso apunte a una variable en otro proceso. ¿Cómo hacerlo entonces? Pues precisamente gracias a shmget(), que crea una zona de memoria en el sistema que luego pueda ser compartida entre procesos. Una vez creada esa zona, quien la creó recibe un identificador entero (shmid) que debe usarse para, mediante shmat(), obtener un puntero (en el espacio virtual del proceso que lo obtiene) que apunte a la zona compartida en el sistema. Es como una "ventanita" en el espacio de direcciones virtuales de cada proceso que permite "asomarse" a la memoria del sistema. Las "ventanitas" de todos los procesos se asoman al mismo trozo de memoria del sistema y así lo comparten, pero ha de ser a través de punteros.
Esto implica que cada hijo debe conocer el valor de shmid para poder mapearlo en su propio espacio de direcciones. Una forma sencilla es pasarle ese valor como parámetro (aunque sólo el padre lo crea).
Por tanto sobra la parte en que llamas a shmget() desde los hijos. Éstos sólo deben hacer shmap(), sobre el  shmid que les pasa el padre.
Cada hijo debe incrementar la suma 100 veces. Imagino que eso quiere decir dentro de un bucle que se repita 100 veces, y no sumando 100 como tú has hecho.
El código de los tres hijos es idéntico, por tanto no veo la necesidad de hacer un if para distinguir cuál de los hijos es. Se puede simplificar por tanto su código.

Hay un fallo adicional relacionado con la concurrencia, pero de momento no voy a entrar en él. Con todo lo antes dicho el programa quedaría así:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#define CHILDREN    3
#define OK  7

void adder(int,int);
// Desaparece la variable suma global

int main()
{
    int i,j, shmid, status;
    key_t key;

    int *suma ;       // La suma en el padre es un puntero
    struct shmid_ds buf;

    //  El padre crea la zona de memoria compartida en el sistema
    key = ftok("adicional2.c", 1);
    if ((shmid = shmget(key, sizeof(int), IPC_CREAT | 0777)) == -1){
         exit(1);
    }
    // Pero debe mapearla en su propio espacio de direcciones
    suma=(int *) shmat(shmid,NULL,0);

    // Ahora ya podemos ponerla a cero, pero recuerda que es un puntero
    *suma=0;

    // creacion hilos
    for (i = 0; i < CHILDREN; i++) {
        pid_t pid = fork();
        if (pid==0) {//cuando fork es igual de 0
            // Esto lo hará cada hijo
            adder(shmid, i);     // Le pasamos el id de la zona compartida
            exit(0);             // y termina aqui
        }
    }

    // Esperar a que los tres hijos acaben
    for (i = 0; i < CHILDREN; i++) {
        pid_t pid = wait(&status);
        printf("\nHijo %d ha terminado status %d\n", pid, WEXITSTATUS(status));
    }

    // Imprimir resultado final, recordemos que es puntero
    printf("\nSuma [%d]\n",*suma);
}

// Esta es la función que ejecutará cada hijo
void adder(int shmid, int id)
{
    // Cada hijo tiene su propio puntero a la zona compartida
    int *suma ;

    // que hay que mapear al espacio de direcciones del hijo
    suma=(int *) shmat(shmid,NULL,0);

    // Ahora el bucle que incrementa 100 veces la suma
    for (int i=0; i<100; i++ ) {
        *suma+=1;
    }
    // Este hijo imprime su resultado
    printf("suma hijo %d= %d\n",id, *suma);
    // exit(OK);  // sobraba este exit, pues ya se hace luego en main
}

Si compilas y ejecutas este programa verás:
suma hijo 0= 100
suma hijo 1= 200
Hijo 19226 ha terminado status 0
Hijo 19227 ha terminado status 0
suma hijo 2= 300
Hijo 19228 ha terminado status 0
Suma [300]

Por tanto ha funcionado.
Sin embargo si lo ejecutas millones de veces, encontrarás algunas en las que el resultado no es 300. Esto puede pasar porque los tres hijos se están ejecutando a la vez y modificando a la vez la misma zona de la memoria, pero la operación:
*suma += 1

no es "atómica" (no tiene lugar en una sola instrucción, aunque en C sea una sola línea). Su ejecución se parece más bien a esto otro:
int temporal;
temporal = *suma;
temporal = temporal + 1;
*suma = temporal;

por tanto podría darse el caso de que un hijo lea *suma, encontrando por ejemplo 10, y mientras le está sumando 1 a su temporal, otro hijo lea también *suma y encuentre todavía 10. Ambos hijos llegarán al resultado 11, y lo guardarán (primero uno y después el otro) en la zona compartida, con lo que en lugar de incrementarse en dos, se habrá incrementado sólo en 1.
Esto es improbable, pero puede ocurrir. Y por tanto técnicamente el programa es incorrecto. Arreglarlo implica usar semáforos o cerrojos, que son otro tipo de objeto compartido gestionado por el operativo y que sirve para que los hijos puedan coordinarse. Un hijo solicita el cerrojo, y mientras incrementa su variable ningún otro hijo podrá hacerlo porque cuando vayan a solicitar el cerrojo éste estará ocupado y permanecerán a la espera hasta obtenerlo. Una vez el incremento ha terminado, el hilo libera el cerrojo, permitiendo de ese modo que otro hilo pueda avanzar. Ese cerrojo por tanto permite que los hijos entren "por turnos" a la instrucción *suma+=1.
Te dejo como ejercicio esta parte de los cerrojos (lee sobre flock()) o semáforos (lee sobre sem_init(), sem_wait() y sem_post().

