Linux Semaphore
主要用到的几个函数
0, ftok
ftok - convert a pathname and a project identifier to a System V IPC key
key_t ftok(char *pathname, char proj_id);
1, semget
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
函数作用:返回一个与参数 key 相关的信号量集。
信号量集被建立的情况有两种:
1.如果键key的值是IPC_PRIVATE (系统内核中没有与参数key相应的信号量存在)
2.或者键key的值不是IPC_PRIVATE,并且键所对应的信号量集不存在,同时标志semflg中指定IPC_CREAT。
2, semctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
因为信号量一般是作为一个信号量集使用的,而不是一个单独的信号量。所以在信号量集的操作中,不但要知道IPC关键字值,也要知道信号量集中的具体的信号量。
系统调用semctl()的第一个参数是信号量集IPC标识符。第二个参数是操作信号在信号集中的编号
参数cmd中可以使用的命令如下:
·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
·IPC_RMID将信号量集从内存中删除。
·GETALL用于读取信号量集中的所有信号量的值。
·GETNCNT返回正在等待资源的进程数目。
·GETPID返回最后一个执行semop操作的进程的PID。
·SETALL设置信号量集中的所有的信号量的值。
·GETZCNT返回正在等待完全空闲的资源的进程数目。
·GETVAL返回信号量集中的一个单个的信号量的值。
·SETVAL设置信号量集中的一个单独的信号量的值。
3, semop
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
参数
semop参数1.semid:信号集的识别码,可通过semget获取。
semop参数3.nsops:信号操作结构的数量,恒大于或等于1。
semop参数2.sops:指向存储信号操作结构的数组指针,信号操作结构的原型如下
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
这三个字段的意义分别为:
sem_num
:操作信号在信号集中的编号,第一个信号的编号是0。
sem_op
:如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,如果没有设置IPC_NOWAIT,则调用该操作的进程或者线程将暂时睡眠,直到信号量的值为0;否则,进程或者线程不会睡眠,函数返回错误EAGAIN。
sem_flg
:信号操作标志,可能的选择有两种
IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
程序semp1.c
初始化时候资源数是1,每次while使用一个资源,没有资源时候就阻塞。
/*************************************************************************
> File Name: semp1.c
> Author: ims
> Created Time: 2018年09月19日 星期三 00时10分38秒
************************************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include<stdlib.h>
#include<stdio.h>
/*
struct sem{
unsigned short semval; // semaphore value
unsigned short semzcnt; // # waiting for zero
unsigned short semncnt; // # waiting for increase
pid_t sempid; // ID of process that did last op
}
*/
int main(void)
{
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
}arg;
arg.val = 1; // 初始化时候资源数是1
printf("The num of available resource is %d \n",arg.val);
key_t key;
if ((key = ftok(".",'c')) == -1)
{
perror("ftok error!\n");
exit(1);
}
printf("key:%d\n",key);
int semid;
if ((semid = semget(key,1,IPC_CREAT|0666)) == -1)
{
perror("semget error!\n");
exit(1);
}
if (semctl(semid,0,SETVAL,arg) == -1)
{
perror("semctl error!\n");
exit(1);
}
/* Each operation is performed on the sem_num-th semaphore of the semaphore set,
* where the first semaphore of the set is numbered 0.
*/
struct sembuf sops;
sops.sem_num = 0; /* Operate on semaphore 0 */
sops.sem_op = -1; /* the absolute value of sem_op is subtracted from semval */
sops.sem_flg = 0;
while (1)
{
if (semop(semid,&sops,1) == -1)
{
perror("semop error!\n");
exit(1);
}
printf("get a resource\n");
}
semctl(semid,0,IPC_RMID,0);//Immediately remove the semaphore set
exit(0);
}
程序semp2.c
每次运行都给semp1.c 程序资源加1,解除它的阻塞状态。
/*************************************************************************
> File Name: semp2.c
> Author: ims
> Created Time: 2018年09月19日 星期三 00时12分15秒
************************************************************************/
#include <sys/types.h>
#include<stdlib.h>
#include <sys/sem.h>
#include<stdio.h>
int main(void)
{
key_t key;
int semid;
if (( key = ftok(".",'c')) == -1)
{
perror("ftok error!\n");
exit(1);
}
if ((semid = semget(key,1,IPC_CREAT|0666)) == -1)
{
perror("semget error!\n");
exit(1);
}
sembuf sops;
sops.sem_num=0;
sops.sem_op=1;
sops.sem_flg=IPC_NOWAIT;
if(semop(semid, &sops, 1) != -1)
{
puts("relese a resource!");
}
exit(0);
}