Я делю память в C между основным процессом и его детьми, но у меня возникают проблемы с синхронизацией их действий - PullRequest
0 голосов
/ 08 июня 2019

У меня есть программа, которая должна сделать это:

  1. Основная программа создает кусок общей памяти (чтобы поделиться со своими будущими детьми) размером структуры с именем ClientInfo, которая содержит 2 целых числа и строку. Затем программа запрашивает у пользователя номер, который хранится в переменной n
  2. Основная программа создает n детей. Затем дети ждут сигнала SIGUSR1 от своего отца.
  3. Основная программа посылает сигнал SIGUSR1 всем своим детям.
  4. Каждый дочерний элемент читает строку из терминала, записывает ее в общую память, а также увеличивает на одну единицу оба общих целых числа. Затем он посылает SIGUSR1 своему отцу, спит от 1 до 10 секунд, а затем заканчивается.
  5. Каждый раз, когда отец получает SIGUSR1, он печатает содержимое общей памяти, а затем заканчивается только тогда, когда заканчиваются все его дети.

«Подвох» заключается в том, что это домашняя работа колледжа, и нам сказали, что отец должен иметь возможность распечатывать содержимое общей памяти один раз для каждого ребенка, то есть всего n раз . Также мы не можем использовать sigwait () или глобальные переменные (если только глобальные переменные не являются единственным способом).

Также каждый раз, когда я запускаю программу, она просто зависает на неопределенный срок, запрашивая n

Я знаю, что должно быть какое-то состояние гонки, но я действительно плох в этом и не могу понять, что не так.

Заранее спасибо.

Вот код:



#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define SHM_NAME "/shm_example"
#define SEM1 "/example_sem1"
#define SEM2 "/example_sem2"

#define NAME_MAX 100


typedef struct{
    int previous_id; //!< Id of the previous client.
    int id; //!< Id of the current client.
    char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;



int main(void) {

    int i,n,*pids;
    int fd_shm;
    int error;
    struct sigaction act;
    ClientInfo *example_struct;
    sigset_t mask, oldmask; 
    sem_t *sem_write = NULL,*sem_read = NULL;

    sigemptyset(&mask);
    sigemptyset(&oldmask);  
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);

    printf("Introduzca un numero:\n");
    scanf("%d",&n);

    if(!(pids = malloc(n*sizeof(int))))
        exit(EXIT_FAILURE);

    if ((sem_write = sem_open(SEM1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    if ((sem_read = sem_open(SEM2, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }


    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;

    act.sa_handler = SIG_IGN;
    if (sigaction(SIGUSR1, &act, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }    



    fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR); 


    if(fd_shm == -1) {
        fprintf (stderr, "Error creating the shared memory segment \n");
        return EXIT_FAILURE;
    }   
    error = ftruncate(fd_shm, sizeof(ClientInfo));

    if(error == -1) {
        fprintf (stderr, "Error resizing the shared memory segment \n");
        shm_unlink(SHM_NAME);
        return EXIT_FAILURE;
    }

    /* Map the memory segment */
    example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);

    if(example_struct == MAP_FAILED) {
        fprintf (stderr, "Error mapping the shared memory segment \n");
        shm_unlink(SHM_NAME);
        return EXIT_FAILURE;
    }


    (example_struct->previous_id)=-1;
    (example_struct->id)=0;



    for(i=0;i<n;i++){
        pids[i] = fork();
        if (pids[i] < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        if (pids[i] == 0) {
            char nombre[NAME_MAX];
            srand(getpid() ^ (i * 1091));
            sigsuspend(&oldmask);
            sem_wait(sem_write);
            (example_struct->previous_id)++;
            printf("Introduzca un nombre:\n");
            scanf("%s",nombre);
            memcpy(example_struct->name, nombre, sizeof(nombre));
            (example_struct->id)++;
            kill(getppid(),SIGUSR1);
            sem_post(sem_write);
            sleep(1 + (rand()%10));
            exit(EXIT_SUCCESS);

        }

    }
    sigprocmask(SIG_UNBLOCK, &mask, &oldmask);
    kill(0,SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);

    while(1){

    sigsuspend(&oldmask);


    /*if(wait(NULL)<0){
       sem_close(sem_write);
       sem_close(sem_read);
       sem_unlink(SEM1);
       sem_unlink(SEM2);
       munmap(example_struct, sizeof(*example_struct));
       shm_unlink(SHM_NAME);
       exit(EXIT_SUCCESS);
    }*/


    sem_wait(sem_read);
    sem_wait(sem_write);
    sem_post(sem_read);

    printf("El cliente es %s con id %d y el previo es %d\n",example_struct->name,example_struct->id,example_struct->previous_id);
    fflush(stdout);
    sigemptyset(&mask); 
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);

    sem_wait(sem_read);
    sem_post(sem_write);
    sem_post(sem_read);}

}

1 Ответ

0 голосов
/ 08 июня 2019

Вы можете попробовать что-то подобное:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdatomic.h>

#define SHM_NAME "/shm_example"

#define NAME_MAX 100


typedef struct{
    char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;


atomic_bool done = ATOMIC_VAR_INIT(false);

void child_handler(int dummy) {
    (void)dummy;
    done = true;
}

int main(void) {

    int i,n,*pids;
    int fd_shm;
    int error;
    struct sigaction act;
    ClientInfo *example_struct;

    printf("Introduzca un numero:\n");
    scanf("%d",&n);

    if(!(pids = malloc(n*sizeof(int))))
        exit(EXIT_FAILURE);

    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;
    act.sa_handler = child_handler;
    if (sigaction(SIGUSR1, &act, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);

    if(fd_shm == -1) {
        fprintf (stderr, "Error creating the shared memory segment \n");
        return EXIT_FAILURE;
    }
    error = ftruncate(fd_shm, sizeof(ClientInfo));

    if(error == -1) {
        fprintf (stderr, "Error resizing the shared memory segment \n");
        shm_unlink(SHM_NAME);
        return EXIT_FAILURE;
    }

    /* Map the memory segment */
    example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);

    if(example_struct == MAP_FAILED) {
        fprintf (stderr, "Error mapping the shared memory segment \n");
        shm_unlink(SHM_NAME);
        return EXIT_FAILURE;
    }

    for (i = 0; i < n ; i++) {
        pids[i] = fork();
        if (pids[i] < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        if (pids[i] == 0) {
            /* Child */
            while (!done) {
                /* Wait for signal */
                sleep(1);
            }
            printf("child %d wakes up\n", getpid());
            sprintf(example_struct->name, "my pid is %d", getpid());
            kill(getppid(),SIGUSR1);
            sleep(1 + (rand()%10));
            exit(EXIT_SUCCESS);
        }
    }

    /* only father here */
    for (i = 0; i < n; i++) {
        done = false;
        kill(pids[i], SIGUSR1);
        printf("Waiting child %d\n", pids[i]);
        while (!done) {
            /* Wait for signal */
            sleep(1);
        }
        printf("Answer from %d: %s\n", pids[i], example_struct->name);
        wait(NULL);
    }
}

В конце концов, я не совсем понимаю, почему вы использовали семафоры, если вас просят использовать только сигнал, поэтому я удалил их. Я также удалил идентификатор, получая менее болтливый код, вы можете добавить их обратно, если вам это нужно.

Суть в том, что я выполняю ожидание с помощью цикла while (), ожидающего логическую атомарную переменную.

Итак, отец подает сигнал первому ребенку, затем ждет, пока он ответит, затем делает то же самое со следующим, и так далее ...

так что вы получите такую ​​последовательность:

$ ./example
Introduzca un numero:
5
Waiting child 14314
child 14314 wakes up
Answer from 14314: my pid is 14314
Waiting child 14315
child 14315 wakes up
Answer from 14315: my pid is 14315
Waiting child 14316
child 14316 wakes up
Answer from 14316: my pid is 14316
Waiting child 14317
child 14317 wakes up
Answer from 14317: my pid is 14317
Waiting child 14318
child 14318 wakes up
Answer from 14318: my pid is 14318
...