Linux System V IPC 信号量模型
- 获取key ftok()
- 创建/获取信号量集 semget()
- 初始化信号量集 semctl()
- 操作信号量集 semop()
- 删除信号量集 semctl()
使用的头文件:
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>ftok()
//获取key值, key值是System V IPC的标识符,成功返回key,失败返回-1设errno//同pathname+同 proj_id==>同key_t;key_t ftok(const char *pathname, int proj_id);pathname :文件名
proj_id: 1~255的一个数,表示project_id
key_t key=ftok(".",100);//“.”就是一个存在且可访问的路径, 100是假设的proj_idif(-1==key)perror("ftok"),exit(-1);semget():
//创建/获取一个信号量集,成功返回semid,失败返回-1int semget(key_t key, int nsems, int semflg);nsems: 信号量集的大小/信号量的个数,0表示获取已经存在的信号量集
semflg- IPC_CREAT :若不存在则创建, 需要在msgflg中"|权限信息"; 若存在则打开
- IPC_EXCL :若存在则创建失败
- 0 :获取已经存在的信号量集
//create semsemid=semget(key,1,IPC_CREAT|IPC_EXCL|0664);if(-1==semid)perror("semid"),exit(-1);semctl()
//主要用于对指定的信号量集/信号量执行指定的操作,成功返回0,失败返回-1设errnoint semctl(int semid, int semnum, int cmd, ...);semid: 信号量集的编号(哪个信号量集)
semnum: 信号量集的下标(这个信号量集里的哪个信号量)
cmd:具体的操作命令
- IPC_STAT 将内核中与semid相关的信息拷贝到arg.buf指向的结构体中
- IPC_SET将buf指向的semid_ds结构体的部分内容写入到内核中的相关数据结构中,同时更新sem_ctime成员
- IPC_RMID 立即销毁指定的信号量集,调用的进程的的effective UID必须和信号量集的创建者或所有者相匹配,或者这个进程有足够的特权级别,此时第四个参数会被忽略
- IPC_INFO(Linux-specific)返回系统对信号量集的限制到__buf指向的结构体seminfo中
//_GNU_SOURCEstructseminfo {int semmap; /* Number of entries in semaphore map; unused within kernel */int semmni; /* Maximum number of semaphore sets */int semmns; /* Maximum number of semaphores in all semaphore sets */int semmnu; /* System-wide maximum number of undo structures; unused within kernel */int semmsl; /* Maximum number of semaphores in a set */int semopm; /* Maximum number of operations forsemop(2) */int semume; /* Maximum number of undo entries per process; unused within kernel */int semusz; /* Size of struct sem_undo */int semvmx; /* Maximum semaphore value */int semaem; /* Max. value that can be recorded for semaphore adjustment (SEM_UNDO) */};//semmsl, semmns, semopm, semmni可以通过/proc/sys/kernel/sem来设置- SEM_INFO (Linux-specific)返回和IPC_INFO一样的信息,除了以下方面:semusz成员返回当前系统中存在的信号量集的数目,semaem返回系统中所有信号量集中的信号量总数
- SEM_STAT(Linux-specific)返回semid_ds结构,类似与IPC_STAT
- GETALL 返回所有信号量的semval到arg.array中,忽略semnum
- GETNCNT 返回信号量集第semnum个信号量的semcnt值
- GETPID 返回信号量集第semnum个信号量的sempid值
- GETVAL 返回信号量集第semnum个信号量的semval值
- GETZCNT 返回信号量集第semnum个信号量的semzcnt值
- SETALL 使用arg.array设置信号量集里的所有的信号量的semval值,同时更新信号量集的semid_ds结构体的sem_ctime成员的值
- SETVAL返回信号量集第semnum个信号量的semval的值到arg.val中,同时更新信号量集的semid_ds结构体的sem_ctime成员的值
the fourth argument:
union semun {intval; /* Value for SETVAL */struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short* array;/* Array for GETALL, SETALL */struct seminfo* __buf;/* Buffer for IPC_INFO(Linux-specific) */};//<sys/sem.h>struct semid_ds {struct ipc_perm sem_perm; /* Ownership and permissions */time_tsem_otime;/* Last semop time */time_tsem_ctime;/* Last change time */unsigned shortsem_nsems;/* No. of semaphores in set */};//<sys/ipc.h>struct ipc_perm {key_t __key;/* Key supplied to semget(2) */uid_t uid;/* Effective UID of owner */gid_t gid;/* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned shortmode; /* Permissions */unsigned short__seq;/* Sequence number */};int res=semctl(semid,0,SETVAL,5);if(-1==res)perror("semctl"),exit(-1);int res=semctl(semid,0,IPC_RMID);if(-1==res)perror("semctl"),exit(-1);semop():
//操作指定的信号量集,成功返回0,失败返回-1设errnoint semop(int semid, struct sembuf *sops, unsigned nsops);semid:信号集的ID(returned by semget())
sops:结构体指针, 既可以指向结构体变量, 也可以指向结构体数组?信号量集本质上是若干个信号量的集合, 可以实现对信号量的批处理
struct sembuf{unsigned shortsem_num;//信号量集的下标short sem_op; //正数表示增加, 0表示不变, 负数表示??小short sem_flg;//操作标志,默认给0}nsops:结构体指针指向的元素个数, 也就是数组的大小
例子
Sys V IPC sem#include<unistd.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#include<signal.h>#include<stdio.h>#include<stdlib.h>int main(){//get keykey_t key=ftok(".",200);if(-1==key)perror("ftok"),exit(-1);printf("key=%d
",key);//create semint semid=semget(key,0,0);if(-1==semid)perror("semget"),exit(-1);printf("semid=%d
",semid);//creat 10 children to take the shared resourceint i=0;for(i=0;i<10;i++){//创建10个进程, 当然,需要只给parent或child单独fork(), 否则就是2^10个进程pid_t pid=fork();if(-1==pid)perror("fork"),exit(-1);if(0==pid){struct sembuf buf;//准备占用资源, sem_op-1buf.sem_num=0;//信号量集下标buf.sem_op=-1;//信号量-1buf.sem_flg=0;//操作标志int res=semop(semid,&buf,1/*结构体变量的个数*/);if(-1==res)perror("semop"),exit(-1);sleep(20);//模拟正在占用共享资源buf.sem_op=1; //占用完了, sem_op+1res=semop(semid,&buf,1);if(-1==res)perror("semop"),exit(-1);exit(0);//终止子进程, 自然也就跳出了循环,防止再fork()//break;}} return 0;}//出现抢占的效果, 还没有全部释放完毕的时候就有进程抢到了已经释放的进程本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-10/135806.htm