Summary of semaphores under Linux II

Use semaphores and pipes

Implement A process to write content to the pipeline, B process does not read immediately, but wait for A process to write and exit before B process reads. Here, processes A and B use semaphores to achieve this effect.

We package semget semop semctl as follows

sem.h

#ifndef __SEM_H

#define __SEM_H

typedef union semun
{
    int val;
}Semun;

int sem_init(int key,int nsems,int semval[]);//return semid

void sem_p(int semid,int sems[],int size);

void sem_v(int semid,int sems[],int size);

void sem_del(int semid);

#endif

sem.c:

#include "sem.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>


int sem_init(int key,int nsems,int semval[])//return semid
{
    int semid = semget((key_t)key,0,0664);
    if(semid != -1)
    {
        return semid;
    }
    semid = semget((key_t)key,nsems,IPC_CREAT|0664);
    assert(semid!=-1);
    int i=0;
    for(;i<nsems;++i)
    {
        Semun sem;
        sem.val = semval[i];
        semctl(semid,i,SETVAL,sem);
    }
    return semid;
}

void sem_p(int semid,int sems[],int size)
{
    struct sembuf buff[size];
    int i = 0;
    for(;i<size;++i)
    {
        buff[i].sem_num = sems[i];
        buff[i].sem_op = -1;
        buff[i].sem_flg = SEM_UNDO;
    }
    semop(semid,buff,size);
}

void sem_v(int semid,int sems[],int size)
{
    struct sembuf buff[size];
    int i = 0;
    for(;i<size;++i)
    {
        buff[i].sem_num = sems[i];
        buff[i].sem_op = 1;
        buff[i].sem_flg = SEM_UNDO;
    }
    
    semop(semid,buff,size);
}

void sem_del(int semid)
{
    if(-1 == semctl(semid,0,IPC_RMID))
    {
        printf("delete error\n");
        exit(0);
    }
}

Related code of process A:

/*================================================================
*   Copyright (C) 2019 Sangfor Ltd. All rights reserved.
*   
*   File name: main.c
*   Created by: gaojie
*   Date of establishment: July 8, 2019
*   Description:
*
================================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#include "sem.h"
#include <fcntl.h>

int main()
{
    int val=0;

    int semid = sem_init(1234,1,&val);
    int fd = open("FIFO",O_WRONLY);
    assert(fd != -1);
    while(1)
    {
        printf("please input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        
        write(fd,buff,strlen(buff)-1);
    }
    int sem = 0;
    sem_v(semid,&sem,1);
    close(fd);
}

Related code of process B

/*================================================================
*   Copyright (C) 2019 Sangfor Ltd. All rights reserved.
*   
*   File name: mainb.c
*   Created by: gaojie
*   Date of establishment: July 8, 2019
*   Description:
*
================================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#include <fcntl.h>
#include "sem.h"

int main()
{
    int val = 0;
    int semid = sem_init(1234,1,&val);

    int fd = open("FIFO",O_RDONLY);
    printf("open FIFO success\n");
    assert(-1!=fd);

    int sem = 0;
    sem_p(semid,&sem,1);
    char buff[1024]={0};
    int n =read(fd,buff,1023);

    if(n<=0)
    {
        printf("error\n");
        exit(0);
    }

    printf("data length = %d \n",strlen(buff));
    printf("%s\n",buff);
    close(fd);
}

If we comment out the semaphore related operations of process A and process B

It can be seen that process B receives and exits after our process A has been input once. Since the pipeline must have A section of reading and A section of writing before it can work normally, after B exits, process A exits with the exit of B.

But we add in the semaphore "blocking" the data received by process B. at this time, process B must wait for process A to release the critical area resources before entering the critical area code.

Posted by BenS on Thu, 31 Oct 2019 06:18:34 -0700