semop()应该等待/阻塞,直到二进制信号量的值变为1,但不要等待

时间:2019-03-29 17:15:07

标签: linux ipc binary-semaphore

在父进程中创建仅包含一个信号量的信号量对象。将信号量初始化为初始值零(0)。 在子进程中执行递减操作,在父进程中执行递增操作。

初始值-0 父级-增量(1) 儿童-减量(0)

在这里我想让父母睡觉一段时间,以便孩子等待信号量值递减,直到父母将其增加到1。

在父母中,我放置sleep(10)并让孩子第一次执行以减少信号量,因此孩子要等10秒钟,直到父母增加信号量为止。

为此,我尝试了两种不同的方法在子进程中实现semop()(使用IPC_NOWAIT和DEFAULT),我将为这两种方法提供代码。 我不明白为什么这两种方法的行为方式不同,因为它们应该产生相同的行为。

使用IPC_NOWAIT的第一种方法:

#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

#define KEY1 12345

union semun {
             int val;
             struct semid_ds *buf;
             unsigned short *array;
             struct seminfo *__buf;
};

int main()
{
    int ret1,ret, sem, id2;
    union semun u1;
    struct sembuf sboa,sb;
    int status;

    sem = semget(KEY1, 1, IPC_CREAT|0600);

    if(sem<0) { perror("error in semaphore creation"); exit(1); }

    u1.val = 0;
    ret1=semctl(sem,0,SETVAL,u1);

    ret1 = semctl(sem,0,GETVAL);
    printf("Initial value of sem - %d\n",ret1);

    ret= fork();
    if(ret<0)
    {
        perror("error in chid");
        exit(1);
    }
    if(ret==0)
    {
        //sleep(1);
        int x;
        ret1 = semctl(sem,0,GETVAL);
        printf("child.....before decrement..the value of sem - %d\n",ret1);
        sboa.sem_num = 0;
        sboa.sem_op = -1;
        sboa.sem_flg = IPC_NOWAIT;

        while ((x = semop(sem, &sboa, 1) < 0))
        {
            if (errno == EAGAIN)
            {
                //printf("Not able to get semaphore, received EAGAIN error\n");
                //printf("child.....before decrement..the value of sem - %d\n",ret1);
                sleep(1); continue;
            }
            else
            {
                perror("exiting now from child as not able to do semop:");
                break;
            }
        }

        ret1 = semctl(sem,0,GETVAL);
        printf("child.....after decrement..the value of sem - %d\n",ret1);
        exit(0);
    }
    if(ret>0)
    {
        int x;
        ret1 = semctl(sem,0,GETVAL);
        printf("parent.....before increment..the value of sem - %d\n",ret1);
        sleep(10);

        sboa.sem_num = 0;
        sboa.sem_op =  +1;
        sboa.sem_flg = 0;

        semop(sem,&sboa, 1);

        ret1 = semctl(sem,0,GETVAL);
        printf("parent....after increment ..the value of sem - %d\n",ret1);
    }

    ret = waitpid(-1,&status,0);
    if(ret > 0 )
    {
        printf("Child with the id: %d terminated\n", ret);
        if(WIFEXITED(status))
        {
            printf("Process exited normally\n");
        }
        else
        {
            printf("Process exited abnormally");
        }
    }
    else
    {
        perror("Error in executing waitpid\n");
        exit(1);
    }

    semctl(sem,0,IPC_RMID);
    return(0);
}

//具有IPC_NOWAIT的输出

Initial value of sem - 0
parent.....before increment..the value of sem - 0
child.....before decrement..the value of sem - 0
parent....after increment ..the value of sem - 1
child.....after decrement..the value of sem - 0
Child with the id: 10284 terminated
Process exited normally

使用默认值的第二种方法:

#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

#define KEY1 12345

union semun {
             int val;
             struct semid_ds *buf;
             unsigned short *array;
             struct seminfo *__buf;
};

int main()
{
    int ret1,ret, sem, id2;
    union semun u1;
    struct sembuf sboa,sb;
    int status;

    sem = semget(KEY1, 1, IPC_CREAT|0600);

    if(sem<0) { perror("error in semaphore creation"); exit(1); }

    u1.val = 0;
    ret1=semctl(sem,0,SETVAL,u1);

    ret1 = semctl(sem,0,GETVAL);
    printf("Initial value of sem - %d\n",ret1);

    ret= fork();
    if(ret<0)
    {
        perror("error in chid");
        exit(1);
    }
    if(ret==0)
    {
        int x;
        ret1 = semctl(sem,0,GETVAL);
        printf("child.....before decrement..the value of sem - %d\n",ret1);
        sboa.sem_num = 0;
        sboa.sem_op = -1;
        sboa.sem_flg = 0;
        semop(sem, &sboa, 1);

        ret1 = semctl(sem,0,GETVAL);
        printf("child.....after decrement..the value of sem - %d\n",ret1);
        exit(0);
    }
    if(ret>0)
    {
        int x;
        ret1 = semctl(sem,0,GETVAL);
        printf("parent.....before increment..the value of sem - %d\n",ret1);
        sleep(10);

        sboa.sem_num = 0;
        sboa.sem_op =  +1;
        sboa.sem_flg = 0;

        semop(sem,&sboa, 1);

        ret1 = semctl(sem,0,GETVAL);
        printf("parent....after increment ..the value of sem - %d\n",ret1);
    }

    ret = waitpid(-1,&status,0);
    if(ret > 0 )
    {
        printf("Child with the id: %d terminated\n", ret);
        if(WIFEXITED(status))
        {
            printf("Process exited normally\n");
        }
        else
        {
            printf("Process exited abnormally");
        }
    }
    else
    {
        perror("Error in executing waitpid\n");
        exit(1);
    }

    semctl(sem,0,IPC_RMID);
    return(0);
}

//使用默认值输出

Initial value of sem - 0
parent.....before increment..the value of sem - 0
child.....before decrement..the value of sem - 0    --> after this the child should have blocked for 10 sec but it continued to print next line
child.....after decrement..the value of sem - 0     --> this line should have printed after 10 sec, how could child get to this line before decrementing semaphore??
parent....after increment ..the value of sem - 1
Child with the id: 10261 terminated
Process exited normally

因此,使用DEFAULT方法时,semop()必须等待父进程将信号量设置为1,但事实并非如此,为什么? 我已经使用IPC_NOWAIT来实现semop(),我们应该始终使用这种方法吗? 解决此类问题的最佳方法/推荐方法是什么? 注意:请同时使用两个代码段作为参考。

0 个答案:

没有答案