【问题标题】:Issue with alternating between parent and child process using POSIX semaphore functions使用 POSIX 信号量函数在父进程和子进程之间切换的问题
【发布时间】:2020-04-30 22:19:15
【问题描述】:

我正在尝试创建一个 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);
}

【问题讨论】:

    标签: c pointers posix semaphore alternating


    【解决方案1】:

    以下建议的代码:

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

    【讨论】:

    • 这也很有帮助和信息量。非常感谢!
    【解决方案2】:
    update((long *)shmp)
    

    这个演员阵容是错误的,毫无意义,是你问题的根源。您不能只使用属于信号量之一的内存作为您自己的计数器。您需要将自己的计数器字段添加到您的 struct 并改为传递指向该字段的指针。

    【讨论】:

    • 当然!当之无愧。
    猜你喜欢
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-19
    相关资源
    最近更新 更多