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

来源:互联网 发布:知乎 代购 吐槽 编辑:程序博客网 时间:2024/05/22 08:06
一.什么是信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。(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、信号量操作come 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);}


0 0
原创粉丝点击