Linux interprocess communication|semaphore

signal

1. Semaphore overview

In a multitasking operating system environment, multiple processes will run at the same time, and there may be a certain correlation between the following processes. Multiple processes may cooperate with each other in order to complete the same task, which forms a synchronization relationship between processes. And between different processes, in order to compete for limited system resources will enter a state of competition, this is the mutual exclusion relationship between processes.
The root of the relationship between synchronization and mutual exclusion lies in critical resources. Critical resources allow only a limited number of processes to access or modify resources at the same time. The code that accesses the critical resource becomes the critical section, and the critical section itself becomes the critical resource.
Semaphore is an inter-process communication mechanism used to solve the problem of synchronization and mutual exclusion between processes. It includes a variable called a semaphore and a process waiting queue waiting for resources under the semaphore, as well as two pairs of semaphores. Atomic operation (PV operation). The semaphore corresponds to a certain resource and takes a non-negative integer value. The semaphore value refers to the amount of the resource currently available. If it is equal to 0, it means that there is no resource currently available.
The specific definition of PV atomic operation is as follows:

  • P operation: if there are available resources (semaphore value> 0), then occupy a resource (semaphore value minus 1, enter the critical section code); if there are no available resources (semaphore value = 0), then be blocked. The system allocates resources to the process
  • V operation: If there is a process waiting for a resource in the waiting queue of the semaphore, wake up a blocked process; if no process is waiting for it, release a resource (the semaphore value is increased by 1)

The simplest semaphore has only two values, 0 and 1. This semaphore is called a binary semaphore.

2. Semaphore programming

2.1 Programming instructions

In Linux systems, the use of semaphores is usually divided into the following steps:

  • Create a semaphore or obtain a semaphore that already exists in the system, use the semget() function
  • Initialize the semaphore, the binary semaphore is usually initialized to 1, using the SETVAL operation of the semctl() function
  • Perform the PV operation of the semaphore and call the semop() function
  • To delete the semaphore, use the IPC_RMID operation of the semctl() function
2.2 Function introduction

semget() function

/*****semget()函数*****/
函数原型:int semget(key_t key, int nsems, int semflg)
传 入 值:key 信号量的键值,多个进程可以通过它访问同一个信号量。IPC_PRIVATE用于创建私有信号量
		 nsems 需要创建的信号量数目,通常为1
		 semflg 同 open() 函数的权限位
返 回 值:成功:返回信号量标识符,在信号量的其他函数中都会使用该值;
		 失败:返回-1

semctl() function

/*****semctl()函数*****/
函数原型:int semctl(int semid, int semnum, int cmd, union semun arg)
传 入 值:semid semget()函数返回的信号量标识符 
		 semnum 信号量编号,使用信号量集时会用到。通常取为0,即使用单个信号量
		 cmd 指定对信号量的各种操作,当使用单个信号量时,常见的操作见下表
		 arg 是union semun结构
返 回 值:成功:根据cmd值的不同返回不同的值;
		 失败:返回-1

//union semun结构的定义
union semun{
    
    
	int val;
	struct semid_ds *buf;
	unsigned short *array;
}
cmd value Corresponding operation meaning
IPC_STAT Get the semid_ds structure of the semaphore and place it in the fourth parameter arg structure
IPC_SETVAL Set the semaphore value to the val value of arg
IPC_GETVAL Returns the current value of the semaphore
IPC_RMID Remove the semaphore from the system

semop() function

/*****semop()函数*****/
函数原型:int semop(int semid, struct sembuf *sops, size_t nsops)
传 入 值:semid semget()函数返回的信号量标识符 
		 sops 指向信号量操作数组
		 nsops 操作数组sops中的操作个数,通常取1
返 回 值:成功:返回信号量标识符,在信号量的其他函数中都会使用该值;
		 失败:返回-1

//sembuf结构体的定义
struct sembuf{
    
    
	short sem_num;	//信号量编号,使用单个信号量时,通常取0
	short sem_op;	//信号量操作,取值-1表示P操作,取值+1表示V操作
	short sem_flg;	//通常设置为SEM_UNDO,表示在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量
}
2.3 Function examples

Because the semaphore-related function calls are more complicated, they can be encapsulated into several basic functions of a single semaphore.

/*****sem_com.c*****/
#include "sem_com.h"
/*信号量初始化函数*/
int init_sem(int sem_id, int init_value){
    
    
	union semun sem_union;
	sem_union.val = init_value;		//init_value为初始值
	if((semctl(sem_id, 0, SETVAL, sem_union)) == -1){
    
    
		perror("Initialize semaphore");
		return -1;
	}
	return 0;
}

/*删除信号量函数*/
int del_sem(int sem_id){
    
    
	union semun sem_union;
	if((semctl(sem_id, 0, IPC_RMID, sem_union)) == -1){
    
    
		perror("Delete semaphore");
		return -1;
	}
}

/*P操作函数*/
int sem_p(int sem_id){
    
    
	struct sembuf sem_b;
	sem_b.sem_num = 0;	//单个信号量的编号为0
	sem_b.sem_op = -1;	//表示P操作
	sem_b.sem_flg = SEM_UNDO;	//系统自动释放将会在系统中残留的信号量
	if(semop(sem_id, &sem_b, 1) == -1){
    
    
		perror("P operation");
		return -1;
	}
	return 0;
}

/*V操作函数*/
int sem_v(int sem_id){
    
    
	struct sembuf sem_b;
	sem_b.sem_num = 0;	//单个信号量的编号为0
	sem_b.sem_op = 1;	//表示V操作
	sem_b.sem_flg = SEM_UNDO;	//系统自动释放将会在系统中残留的信号量
	if(semop(sem_id, &sem_b, 1) == -1){
    
    
		perror("V operation");
		return -1;
	}
	return 0;
}

The following examples illustrate the concept and basic usage of the semaphore

/*****fork.c*****/
//头文件省略
int main(){
    
    
	pid_t result;
	int sem_id;

	sem_id = semget(ftok(".",'a'), 1, 0666|IPC_CREAT);	//创建一个信号量
	init_sem(sem_id, 0);

	result = fork();	//调用fork()函数
	if(result == -1)
		perror("Fork\n");
	else if(result == 0){
    
    	//子进程
		printf("Child process will wait for some seconds...");
		sleep(3);
		printf("The returned value is %d in the child process (PID = %d)\n",result,getpid());
		sem_v(sem_id);
	}
	else{
    
     	//父进程
		sem_p(sem_id);
		printf("The returned value is %d in the father process (PID = %d)\n",result,getpid());
		sem_v(sem_id);
		del_sem(sem_id);
	}
	exit(0);
}

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108306405