博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
System V 信号量
阅读量:5886 次
发布时间:2019-06-19

本文共 6511 字,大约阅读时间需要 21 分钟。

System V 信号量在内核中维护,其中包括二值信号量 、计数信号量、计数信号量集。

二值信号量 : 其值只有0、1 两种选择,0表示资源被锁,1表示资源可用;
计数信号量:其值在0 和某个限定值之间,不限定资源数只在0 1 之间;
计数信号量集 :多个信号量的集合组成信号量集
内核维护的信号量集结构信息如下:定义在头文件<sys/sem.h>

struct semid_ds {    struct     ipc_perm     sem_perm;    struct     sem          *sem_base;    ushort                  sem_nsems;    time_t                  sem_otime;    time_t                  sem_ctime;};

其中ipc_perm 结构是内核给每个进程间通信对象维护的一个信息结构,其成员包含所有者用户id,所有者组id、创建者及其组id,以及访问模式等;semid_ds结构体中的sem结构是内核用于维护某个给定信号量的一组值的内部结构,其结构定义:

struct sem {   int semval;     /* current value */   int sempid;     /* pid of last operation */   struct list_head sem_pending; /* pending single-sop operations */ };

其中senval变量代表当前信号量的值,sempid 为最后一个成功操作该信号量的进程id,该结构体在内核以双向链表进行 维护

semid_ds结构体中的sem_nsems成员代表该信号量标示符的信号量个数
主要函数介绍:

创建一个信号量或访问一个已经存在的信号量集。

int semget(key_t key, int nsems, int semflg);
该函数执行成功返回信号量标示符,失败返回-1
参数key是通过调用ftok函数得到的键值,nsems代表创建信号量的个数,如果只是访问而不创建则可以指定该参数为0,我们一旦创建了该信号量,就不能更改其信号量个数,只要你不删除该信号量,你就是重新调用该函数创建该键值的信号量,该函数只是返回以前创建的值,不会重新创建;
semflg 指定该信号量的读写权限,当创建信号量时不许加IPC_CREAT ,若指定IPC_CREAT |IPC_EXCL则创建是存在该信号量,创建失败。

通过semget函数创建一个信号量集程序如下:(semsemget.c)

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #define SEM_R 0400 //用户(属主)读 7 #define SEM_A 0200 //用户(属主)写 8 #define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6) 9 10 int main(int argc,char *argv[])11 {12 int c,oflag,semid,nsems;13 oflag = SVSEM_MODE | IPC_CREAT; //设置创建模式14 //根据命令行参数e判断是否制定了IPC_EXCL模式15 while((c = getopt(argc,argv,"e"))!= -1) 16 {17 switch(c)18 {19 case 'e':20 oflag |= IPC_EXCL;21 break;22 }23 }24 //判断命令行参数是否合法25 if (optind != argc -2)26 {27 printf("usage: semcreate [-e]
");28 exit(0);29 }30 //获取信号量集合中的信号量个数31 nsems = atoi(argv[optind+1]);32 //创建信号量,通过ftok函数创建一个key,返回信号量 标识符33 semid = semget(ftok(argv[optind],0),nsems,oflag);34 exit(0);35 }

打开一个信号量集后,对其中一个或多个信号量的操作。

int semop(int semid, struct sembuf *sops, unsigned nsops);
该函数执行成功返回0,失败返回-1;
第一个参数semid 为信号量标示符;nops为第二个参数的操作数组的个数,第二个参数sops为一个结构体数组指针,结构体定义在sys/sem.h中,结构体如下

struct sembuf {   unsigned short sem_num; /* semaphore index in array */   short sem_op; /* semaphore operation */   short sem_flg; /* operation flags */};

sem_num 操作信号的下标,其值可以为0 到nops

sem_flg为该信号操作的标志:其值可以为0、IPC_NOWAIT 、 SEM_UNDO
0 在对信号量的操作不能执行的情况下,该操作阻塞到可以执行为止;
IPC_NOWAIT 在对信号量的操作不能执行的情况下,该操作立即返回;
SEM_UNDO当操作的进程推出后,该进程对sem进行的操作将被取消;
sem_op取值 >0 则信号量加上它的值,等价于进程释放信号量控制的资源
sem_op取值 =0若没有设置IPC_NOWAIT, 那么调用进程将进入睡眠状态,直到信号量的值为0,否则进程直接返回
sem_op取值 <0则信号量加上它的值,等价于进程申请信号量控制的资源,若进程设置IPC_NOWAIT则进程再没有可用资源情况下,进程阻塞,否则直接返回。

采用setmop函数对一个信号量执行操作程序如下:(semop.c)

1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 int main(int argc,char *argv[]) 8 { 9 int c,i,flag,semid,nops;10 struct sembuf *ptr;11 flag = 0;12 //根据命令行参数设置操作模式13 while( ( c = getopt(argc,argv,"nu")) != -1)14 {15 switch(c)16 {17 case 'n':18 flag |= IPC_NOWAIT; //非阻塞19 break;20 case 'u':21 flag |= SEM_UNDO; //不可恢复22 break;23 }24 }25 if(argc - optind < 2)26 {27 printf("usage: semops [-n] [-u]
operation...");28 exit(0);29 } 30 //打开一个已经存在的信号量集合31 if((semid = semget(ftok(argv[optind],0),0,0)) == -1)32 {33 perror("semget() error");34 exit(-1);35 }36 optind++; //指向当前第一个信号量的位置37 nops = argc - optind; //信号量个数38 ptr = calloc(nops,sizeof(struct sembuf));39 for(i=0;i

对信号量执行各种控制操作。

int semctl(int semid, int semnum, int cmd, ...);
该函数执行成功返回非负值,失败返回-1
参数semid为信号集的标识符,参数 semnum标识一个特定信号,该参数仅用于 SETVAL、GETVAL、GETPID命令
cmd控制类型,...说明函数参数是可选的,通过该共用体变量semun选择操作参数,各字段如下:

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

IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。

IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID将信号量集从系统中删除
GETALL用于读取信号量集中的所有信号量的值,存于semnu的array中
SETALL 设置所指定的信号量集的每个成员semval的值
GETPID返回最后一个执行semop操作的进程的PID。
LSETVAL把的val数据成员设置为当前资源数
GETVAL把semval中的当前值作为函数的返回,即现有的资源数,返回值为非负数。

调用semctl函数设置信号量的值程序如下(semsetvalues.c):

1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 //定义信号量操作共用体结构 8 union semun 9 {10 int val;11 struct semid_ds *buf;12 unsigned short *array;13 };14 15 int main(int argc,char *argv[])16 {17 int semid,nsems,i;18 struct semid_ds seminfo;19 unsigned short *ptr;20 union semun arg;21 if(argc < 2)22 {23 printf("usage: semsetvalues
[values ...]");24 exit(0);25 }26 //打开已经存在的信号量集合27 semid = semget(ftok(argv[1],0),0,0);28 arg.buf = &seminfo;29 //获取信号量集的相关信息30 semctl(semid,0,IPC_STAT,arg);31 nsems = arg.buf->sem_nsems; //信号量的个数32 if(argc != nsems + 2 )33 {34 printf("%s semaphores in set,%d values specified",nsems,argc-2);35 exit(0);36 }37 //分配信号量38 ptr = calloc(nsems,sizeof(unsigned short));39 arg.array = ptr;40 //初始化信号量的值41 for(i=0;i

 调用semctl获取信号量的值,程序如下(semgetvalues.c):

1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 union semun 8 { 9 int val;10 struct semid_ds *buf;11 unsigned short *array;12 };13 14 int main(int argc,char *argv[])15 {16 int semid,nsems,i;17 struct semid_ds seminfo;18 unsigned short *ptr;19 union semun arg;20 if(argc != 2)21 {22 printf("usage: semgetvalues
");23 exit(0);24 }25 //打开已经存在的信号量26 semid = semget(ftok(argv[1],0),0,0);27 arg.buf = &seminfo;28 //获取信号量集的属性,返回semid_ds结构29 semctl(semid,0,IPC_STAT,arg);30 nsems = arg.buf->sem_nsems; //信号量的数目31 ptr = calloc(nsems,sizeof(unsigned short));32 arg.array = ptr;33 //获取信号量的值34 semctl(semid,0,GETALL,arg);35 for(i=0;i

System V 信号量是具有内核的持续性,可以结合上面介绍的三个函数和程序进行简单的测试。测试结果如下所示:

演示SEM_UNDO属性,测试结果如下:

转载于:https://www.cnblogs.com/Anker/archive/2013/01/14/2859352.html

你可能感兴趣的文章
模拟select控件&&显示单击的坐标&&用户按下键盘,显示keyCode
查看>>
Mac-OSX下Ruby更新
查看>>
jsp九个内置对象
查看>>
[Python笔记][第一章Python基础]
查看>>
Bloomberg SEP 12.x 迁移小记
查看>>
生日小助手V1.1发布了——拥有更整齐的信息列表
查看>>
代理模式
查看>>
Qt 学习(1)
查看>>
MFC CEdit改变字体大小的方法
查看>>
java 中文数字排序方法
查看>>
centos 关于防火墙的命令
查看>>
openstack 源码分析
查看>>
idea 使用maven plugin tomcat 运行正常,无法进入debug模式
查看>>
Classification Truth Table
查看>>
JVM学习:对象的创建和内存分配
查看>>
C++ 静态变量 全局变量 const
查看>>
vs 高级保存选项的设置
查看>>
软件工程敏捷开发04
查看>>
Practise Site Home Sample Page Codes de carte cadeau Amazon | Codes Promo Amazon
查看>>
linux c下输入密码不回显
查看>>