Проблема с чередованием между родительским и дочерним процессами с использованием функций семафора POSIX - PullRequest
1 голос
/ 01 мая 2020

Я пытаюсь создать программу C, в которой счетчик увеличивается путем чередования между родителем и потомком, используя функции семафора POSIX. Пока что у меня возникли проблемы с его использованием, учитывая, что я впервые использую функции семафоров. Если с моей программой что-то не так, некоторые указатели были бы хорошими.

Пока что кажется, что ребенок вообще не увеличивается, и я не уверен, почему это происходит. Программа также действует странно в начале, оставаясь у ребенка, прежде чем чередовать его с родителем.

Результаты программы на данный момент:

GOT EM - parent: expected 0, got 0
GOT EM - child: expected 1, got 1
    child: expected 3, got 1
    child: expected 5, got 1
    child: expected 7, got 1
    child: expected 9, got 1
    child: expected 11, got 1
    child: expected 13, got 1
    child: expected 15, got 1
    child: expected 17, got 1
    child: expected 19, got 1
    child: expected 21, got 1
    child: expected 23, got 1
    child: expected 25, got 1
    child: expected 27, got 2
    child: expected 29, got 2
    child: expected 31, got 2
    child: expected 33, got 2
    child: expected 35, got 2
    child: expected 37, got 2
GOT EM - parent: expected 2, got 2
    child: expected 39, got 2
    child: expected 41, got 3
GOT EM - parent: expected 4, got 4
    child: expected 43, got 4
GOT EM - parent: expected 6, got 6
    child: expected 45, got 6
GOT EM - parent: expected 8, got 8
    child: expected 47, got 8
GOT EM - parent: expected 10, got 10
    child: expected 49, got 10

Моя программа:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>

#define NLOOPS  1000
#define SIZE    sizeof(long)    /* size of shared memory area */

struct shmbuf{
    sem_t child;
    sem_t parent;
};

static int update(long *ptr)
{
     return((*ptr)++);      /* return value before increment */
}

int main(void)
{
    int     fd, i, counter;
    pid_t   pid;
    struct shmbuf   *shmp;


    if ((fd = open("/dev/zero", O_RDWR)) < 0)
        perror("open error");

    ftruncate(fd, sizeof(struct shmbuf));

    if ((shmp = mmap(0, sizeof(struct shmbuf), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
        perror("mmap error");

    close(fd);



    sem_init(&shmp->child, 1, 0);       
    sem_init(&shmp->parent, 1, 1);       /*  Parent first */


    if ((pid = fork()) < 0) {
        perror("fork error");
    } else if (pid > 0) {           /* parent */
        for (i = 0; i < NLOOPS; i += 2) {

            sem_wait(&shmp->parent);

            if ((counter = update((long *)shmp)) != i)
                printf("    parent: expected %d, got %d\n", i, counter);
            else
                printf("GOT EM - parent: expected %d, got %d\n", i, counter);

            sem_post(&shmp->child);     
        }
    } else {                        /* child */
        for (i = 1; i < NLOOPS + 1; i += 2) {

            sem_wait(&shmp->child);

            if ((counter = update((long *)shmp)) != i)
                printf("    child: expected %d, got %d\n", i, counter);
            else
                printf("GOT EM - child: expected %d, got %d\n", i, counter);

            sem_post(&shmp->parent);    
        }   
    }

    exit(0);
}

Ответы [ 2 ]

1 голос
/ 01 мая 2020

следующий предложенный код:

  1. заставляет компилятор выдавать предупреждение о том, что не проверяемое возвращаемое значение из ftruncate().
  2. выполняет желаемую функциональность, за исключением того, что не увеличивает счетчик, используемый в операторах printf() для значения 'got'. Я оставлю это вам для реализации.
  3. Правильно обрабатывает очистку и завершение программы после любых ошибок.
  4. не использует адрес семафора в качестве «длинного» счетчика.

реализует исправления для следующих проблем:

относительно:

static int update(long *ptr) 
{ 
    return((*ptr)++); /* return value before increment */ 
} 

ptr объявлен для указания на long, но возвращаемый тип - int.

относительно:

if ((pid = fork()) < 0) 
    perror("fork error"); 

это 'show stopper', поэтому следующий оператор должен быть:

exit( EXIT_FAILURE ); 

НЕ продолжать выполнение программы, как будто вызов чтобы fork() были успешными.

относительно:

if ((shmp = mmap(0, sizeof(struct shmbuf), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
    perror("mmap error"); 

эта ошибка является 'show stopper', поэтому следующий оператор должен быть:

exit( EXIT_FAILURE ); 

Не продолжается выполнить программу так, как если бы вызов mmap () был успешным.

относительно:

if ((fd = open("/dev/zero", O_RDWR)) < 0) 
    perror("open error"); 

эта ошибка является 'show stopper', поэтому при возникновении этой ошибки следующий оператор должен быть:

exit( EXIT_FAILURE ); 

НЕ продолжать выполнение программы, как если бы вызов open() был успешным

А теперь предложенный код:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>


#define NLOOPS  1000
//#define SIZE    sizeof(long)    /* size of shared memory area */


struct shmbuf
{
    sem_t child;
    sem_t parent;
};


static int update( int *ptr)
{
     return((*ptr)++);      /* return value before increment */
}


int main(void)
{
    int     fd;
    int     i;
    int     counter = 0;
    pid_t   pid;
    struct shmbuf   *shmp;


    if ((fd = open("/dev/zero", O_RDWR)) < 0)
    {
        perror("open error");
        exit( EXIT_FAILURE );
    }

    ftruncate(fd, sizeof(struct shmbuf));

    if ((shmp = mmap(0, sizeof(struct shmbuf), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
    {
        perror("mmap error");
        close(fd);
        exit( EXIT_FAILURE );
    }

    close(fd);



    sem_init(&shmp->child, 1, 0);       
    sem_init(&shmp->parent, 1, 1);       /*  Parent first */


    if ((pid = fork()) < 0) 
    {
        perror("fork error");
        munmap( shmp, sizeof( struct shmbuf ) );
        exit( EXIT_FAILURE );
    }

    else if (pid > 0) 
    {           /* parent */
        for (i = 0; i < NLOOPS; i += 2) 
        {
            sem_wait(&shmp->parent);

            if ((counter = update( &counter )) != i)
                printf("    parent: expected %d, got %d\n", i, counter);
            else
                printf("GOT EM - parent: expected %d, got %d\n", i, counter);

            sem_post(&shmp->child);     
        }
    }

    else 
    {                        /* child */
        for (i = 1; i < NLOOPS + 1; i += 2) 
        {
            sem_wait(&shmp->child);

            if ((counter = update( &counter ) != i))
                printf("    child: expected %d, got %d\n", i, counter);
            else
                printf("GOT EM - child: expected %d, got %d\n", i, counter);

            sem_post(&shmp->parent);    
        }   
    }

    exit(0);
}
1 голос
/ 01 мая 2020
update((long *)shmp)

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

...