Linux ipc------System V信号量

时间:2022-05-27 15:17:25
一.什么是信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。(1)信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。(2)若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。


二.信号量的分类
在学习信号量之前,我们必须先知道——Linux提供两种信号量:
(1)内核信号量,由内核控制路径使用(驱动开发中使用)
(2)用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量。
POSIX信号量又分为有名信号量和无名信号量。
(1)有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步。
(2)无名信号量,其值保存在内存中。


三、POSIX 信号量与SYSTEM V信号量的比较
1. 对POSIX来说,信号量是个非负整数。常用于线程间同步
而SYSTEM V信号量则是一个或多个信号量的集合,它对应的是一个信号量结构体,这个结构体是为SYSTEM V IPC服务的,信号量只不过是它的一部分。常用于进程间同步
2.POSIX信号量的引用头文件是“<semaphore.h>”,而SYSTEM V信号量的引用头文件是“<sys/sem.h>”,它通常依赖于另两个头文件:

  1. #include <sys/types.h>  
  2. #include <sys/ipc.h>

3.从使用的角度,System V信号量是复杂的,而Posix信号量是简单。比如,POSIX信号量的创建和初始化或PV操作就很非常方便。


四、System V 信号量函数定义如下:

1、创建信号量集合come from /usr/include/sys/sem.h

函数原型:int semget(key_t key,int nsems,int semflg);

参数解释

       key:所创建或打开信号量集的键值。需要是唯一的非零整数。

  nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。几乎总是取值为1.

  flag:调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过or表示


2、控制信号量集合、信号量come from /usr/include/sys/sem.h

函数原型:int semctl(int semid,int semnum,int cmd,union semun)

参数解释:

sem_id是由semget返回的信号量标识符。

sem_num:表示集合中信号量的编号。

cmd:表示对信号量的操作。(1)对信号量集的操作(2)对单个信号量的操作

       semun联合结构的定义:

  1. semun是在linux/sem.h中定义的:  
  2.   /*arg for semctl systemcalls.*/  
  3.   union semun{  
  4.   int val;/*value for SETVAL*/  
  5.   struct semid_ds *buf;/*buffer for IPC_STAT&IPC_SET*/  
  6.   ushort *array;/*array for GETALL&SETALL*/  
  7.   struct seminfo *__buf;/*buffer for IPC_INFO*/  
  8.   void *__pad;   

3、 信号量操作 c ome from /usr/include/sys/sem.h

    函数原型:int semop( int semid, struct sembuf semoparray[], size_t nops )

参数解释:

参数semid:是一个通过semget函数返回的一个信号量标识符

参数nops:标明了参数semoparray所指向数组中的元素个数

参数semoparray:是一个struct sembuf结构类型的数组指针,结构sembuf:来说明所要执行的操作,其定义如下:

  1. struct sembuf{  
  2.   unsigned short sem_num;  
  3.   short sem_op;  
  4.   short sem_flg;  
  5.   } 

sem_num是操作的信号量编号

sem_op是信号量的操作,值是一个整数,通常只会用到两个值:1----P操作,-1---V操作。

sem_flg说明函数semop的行为。通常被设置为SEM_UNDO。


五、实例程序

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

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

static int semaphore_p(void);
static int semaphore_v(void);
static int set_semvalue(void);
static int get_semvalue(void);

union semun 
{
        int val;                   			/* value for SETVAL */
        struct semid_ds *buf;       		/* buffer for IPC_STAT, IPC_SET */
        unsigned short int *array;  		/* array for GETALL, SETALL */
        struct seminfo *__buf;      		/* buffer for IPC_INFO */
};

int sem_id;
int main(int argc,char *argv)
{
	pid_t pid;
	int i;
	int value;
    key_t key;
	int status;
	if((pid=fork())==-1)
	{
		perror("fork");
		exit(EXIT_FAILURE);
	}
	else if(pid==0)
	{	
		if((sem_id=semget((key_t)123456,1,IPC_CREAT|0770))==-1)
		{
			perror("semget");
			exit(EXIT_FAILURE);
		}
		if (!set_semvalue()) 
		{
			fprintf(stderr, "Failed to initialize semaphore\n");
			exit(EXIT_FAILURE);
		}
		
			value=get_semvalue();
			printf("this is child,the current value is %d\n",value);
			if(!semaphore_v())
			{
				fprintf(stderr, "Failed to v operator\n");
				exit(EXIT_FAILURE);
			}
			value=get_semvalue();
			printf("the child %d V operator,value=%d\n",i,value);
		
		printf("child exit success\n");
		exit(EXIT_SUCCESS);	
	}
	else	//parent
	{
		sleep(3);
		if((sem_id=semget((key_t)123456,1,IPC_CREAT|0770))==-1)
		{
			perror("semget");
			exit(EXIT_FAILURE);
		}

			value=get_semvalue();
			printf("this is parent ,the current value is %d\n",value);
		printf("the parent will remove the sem\n");
		if(semctl(sem_id,0, IPC_RMID,(struct msquid_ds*)0)==-1)
		{
			perror("semctl");
			exit(EXIT_FAILURE);
		}
		return 0;
	}
}

static int set_semvalue(void)
{
    union semun sem_union;
	int value;
    sem_union.val = 5;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
    printf("set value success,");
	printf("init value is %d\n",get_semvalue());
	return(1);
}

static int get_semvalue(void)
{
		int res;
		if((res=semctl(sem_id, 0, GETVAL)) == -1) 
    	{
    		perror("semctl");
			exit(EXIT_FAILURE);
    	}
		return res;
}
    
static int semaphore_v(void)
{
    	struct sembuf sem_b;
    
    	sem_b.sem_num = 0;
    	sem_b.sem_op = 1; /* V() */
    	//sem_b.sem_flg = SEM_UNDO;
    	sem_b.sem_flg=0;
	if (semop(sem_id, &sem_b, 1) == -1) 
    	{
    		perror("semop");
		return(0);
    	}
    return(1);
}