Communication between unix/linux processes——semaphore

Introduction to semaphores

A semaphore is a counter used for synchronization between processes and threads, and for access to critical resources. A critical resource can be a piece of code or a parameter, etc. If the semaphore value is greater than or equal to 0, it means that the process can access the critical resource, and if it is less than 0, it means that the process is waiting to use the critical resource. That is, a semaphore is a number greater than or equal to or less than 0, which grants a process or thread the right to access or execute a certain program or call a certain parameter.

Semaphore related functions

Create a semaphore

int semget(key_t key, int nsems, int semflg);

parameter:

key: key value

nsems: Create the number of semaphores in the semaphore set, only useful when creating semaphores

semflg:

0: Obtain the semaphore level identifier, if it does not exist, an error will be reported

IPC_CREAT: does not exist to create a semaphore, returns if it exists

IPC_EXCL: Used in conjunction with IPC_CREAT, if it does not exist, it will be created, if it exists, it will report an error

return value:

Successful execution returns the semaphore identifier, failure returns -1

Creating a semaphore is affected by system information

SEMMNI: The total maximum number of semaphores in the system

SEMMSL: The maximum number of semaphore elements in each semaphore

SEMMNS: The total maximum value of the semaphore elements in the semaphore in the system

Semaphore initialization

int semctl(int semid, int semnum, int cmd, ...);

parameter:

semid: semaphore identification

Semnum: The subscript of the semaphore set array, indicating a certain signal

cmd:

IPC_STAT retrieves the semid_ds structure from the semaphore set and stores it in the parameter of the semun union

In the address of member buf

IPC_SET sets the value of the ipc_perm field in the semid_ds structure of a semaphore set, and from

Take out the value from semun’s buf

IPC_RMID removes the semaphore set from the kernel

GETALL gets the values of all semaphores from the semaphore collection and stores their integer values in semun

in an array of pointers to union members

GETNCNT returns the number of processes currently waiting for resources

GETPID returns the PID of the last process that executed the system call semop()

GETVAL returns the value of a single semaphore in the semaphore set

GETZCNT returns the number of processes currently waiting for 100% resource utilization

SETALL is just the opposite of GETALL

SETVAL sets the value of a single semaphore in the semaphore set with the value of the val member in the union

union semun

{

short val; /*value for SETVAL*/

struct semid_ds* buf; /* semid_ds structure for IPC_STAT and IPC_SET*/

unsigned short* array; /*array value for SETALL and GETALL*/

struct semiinfo *_buf; /* cache for controlling IPC_INFO*/

}

struct semid_ds

{
struct ipc_perm sem_perm; //permission related information
time_t sem_otime; //The information of the last semop()
tien_t sem_ctime; //last state change time
unsigned short sem_nsems; //Number of semaphore elements
}

return value:

Successful execution returns -1, failure returns -1

PV operation

int semop(int semid, struct sembuf *sops, unsigned nsops);

parameter:

semid: semaphore identifier

nsops: the number of elements in the result body array (created when there are multiple signals, and use the array allocation operation when operations are required

operation, here is the number of operation signals)

sops:

struct sembuf
{
short semnum; /*The semaphore number in the semaphore set, 0 means

The first semaphore */
short val;
/*
l>0:V operation semaphore value plus val, process release control

H
<0: P operation signal value minus val, (semval-val)

<0 (semval is the semaphore value), the calling process is blocked
IPC_NOWAIT: will not sleep, the process returns directly

EAGAIN error
=0: Blocking and waiting for the semaphore to be 0, the calling process goes to sleep

sleep state until the signal value is 0
IPC_NOWAIT: The process will not sleep and return directly

EAGAIN error
short flag; /*
0; set the default operation of the semaphore
IPC_NOWAIT: set semaphore operation does not wait
SEM_UNDO: The kernel records the UNDO of the calling process

Record, process crash, restore signal according to UNDO record

Quantity count value
*/
}

return value:

Successful execution returns 0, failure returns -1

demo1:

1. Create a parent-child process

2. The child process obtains the signal execution permission, prints son, and returns the permission

3. The parent process obtains the signal execution permission, prints father, and returns the permission

Code example:

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

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

void get_atu(int semiid)
{
        struct sembuf sops;
        sops.sem_num = 0;
        sops.sem_op = 1;
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops,1);
}

void return_atu(int semiid)
{
        struct sembuf sops;
        sops.sem_num = 0;
        sops.sem_op = -1;
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops,1);
}

void result()
{
        key_t key;
        int semi;
        int pid;
        key = ftok(".",128);
        if(key == -1)
        {
                printf("create key fail\
");
                perror("why");
                exit(-1);
        }
        semid = semget(key,1,IPC_CREAT|0777);
        if(semi == -1)
        {
                printf("create sign fail\
");
                perror("why");
                exit(-1);
        }
        union semun init_sign;
        init_sign.val = 0;
        semctl(semid,0,SETVAL,init_sign);
        pid = fork();
        if(pid == 0)
        {
                get_atu(semid);
                printf("son\
");
                return_atu(semid);
        }
        else if(pid > 0)
        {
                get_atu(semid);
                printf("father\
");
                return_atu(semid);
        }
        else
        {
                printf("create fork fail\
");
                perror("why");
                exit(-1);
        }
}

int main()
{
        result();
        return 0;
}

Example of results:

demo2:

1. Write a program, create a shared memory, and write hello word

2. Write a program, get the permission signal, read the shared memory, and release the permission

Code example:

create_shm

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

void result()
{
                key_t key;
                int shmid;
                char *context = "hello word";
                char *shmaddr = NULL;
                key = ftok(".",128);
                if(key == -1)
                {
                                printf("crate key fail\
");
                                perror("why");
                                exit(-1);
                }
                shmid = shmget(key,20,IPC_CREAT|0777);
                if(shmid == -1)
                {
                                printf("crate show memory fail\
");
                                perror("why");
                                exit(-1);
                }
                shmaddr = shmat(shmid,0,0);
                if(shmaddr == NULL)
                {
                                printf("show memory mapping fail\
");
                                perror("why");
                                exit(-1);
                }
                strcpy(shmaddr, context);
                sleep(10);
                shmctl(shmid, IPC_RMID, NULL);
                shmdt(shmaddr);
}

int main()
{
                result();
                return 0;
}

signal_shm

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

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

void get_key(int semiid)
{
                struct sembuf sops;
                sops.sem_num = 0;
                sops.sem_op = 2;
                sops.sem_flg = SEM_UNDO;
                semop(semid, &sops,1);
}

void return_key(int semiid)
{
                struct sembuf sops;
                sops.sem_num = 0;
                sops.sem_op = -2;
                sops.sem_flg = SEM_UNDO;
                semop(semid, &sops,1);
}

void read_shm(int key)
{
                int shmid;
                char *shmaddr = NULL;
                shmid = shmget(key,20,IPC_CREAT|0777);
                shmaddr = shmat(shmid,0,0);
                printf("show memory : %s\
",shmaddr);
                shmctl(shmid, IPC_RMID, NULL);
}

void result()
{
                key_t key;
                int semi;
                key = ftok(".",128);
                if(key == -1)
                {
                                printf("create key fail\
");
                                perror("why");
                                exit(-1);
                }
                semid = semget(key,1,IPC_CREAT|0777);
                union semun init_sem;
                init_sem.val = -1;
                semctl(semid,0,SETVAL);
                get_key(semid);
                read_shm(key);
                return_key(semid);
}

int main()
{
                result();
                return 0;
}

Example of results: