11.1 概述
- 二值信号量:值为0或1的信号量
- 计数信号量:在0和某个限制值之间的信号量
- 计数信号量集:一个或多个信号量(构成一个集合),其中每个都是计数信号量。集合的信号量数存在一个限制
- 对每个信号量集,内核维护一下如下信息结构:
struct semid_ds {
struct ipc_perm ipc_perm; 权限
struct sem *sem_base;
ushort sem_nsems;
time_t sem_otime;
time_t sem_ctime;
};
- 上述结构体中的
struct sem
用于维护某个给定信号量的一组值的内部数据结构:
struct sem {
int semval;
pid_t sempid;
int semncnt;
int semzcnt;
};
11.2 semget()函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
- key: system v ipc对象的key
- nsems: 你要创建的信号量集中的信号量的数量。
如果我们不是创建而是打开一个已经存在的信号量集,此处参数可以指定为0.一旦创建完一个信号量集,其信号量的个数就不能改变啦。
- semflg:标志位
- SEM_R :用户属组读
- SEM_A :用户属组改写
- 可以和 IPC_CREAT | IPC_EXCL 按位与
11.3 semop函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
int semtimedop(int semid, struct sembuf *sops, size_t nsops,const struct timespec *timeout);
- 在system v 信号量集中,对某个信号量的P/V操作,是用结构体 struct sembuf来描述的,即opsptr指向的结构体
struct sembuf
{
short sem_num;
short sem_op;
short sem_flg;
};
- nops 指出opsptr指向结构体数组中元素的个数,表示表多少个信号量进行p/v操作
- 返回值:成功返回0,失败返回-1, 同时errrno被设置。
11.4 semctl函数
int semctl(int semid, int semnum, int cmd, ...);
11.5 system v 实现一个简单的文件锁
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#define SEM_R 0400
#define SEM_A 0200
#define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6)
union semun{
int val ;
struct semid_ds *buf;
ushort *array;
};
#define LOCK_PATH "/tmp/svsemlock"
#define MAX_TRIES 10
int semid,initflag;
struct sembuf postop,waitop;
void my_lock(int fd){
int oflag,i;
union semun arg;
struct semid_ds seminfo;
int flag=0;
if(initflag==0){
oflag = IPC_CREAT | IPC_EXCL | SVSEM_MODE;
if( (semid=semget(ftok(LOCK_PATH,0),1,oflag))>=0 ){
arg.val=1;
flag=semctl(semid,
0,
SETVAL,
arg);
}else if(errno==EEXIST){
semid = semget(ftok(LOCK_PATH,0),1,SVSEM_MODE);
assert(semid!=-1);
arg.buf = &seminfo;
for(i=0;i<MAX_TRIES;i++){
flag=semctl(semid,
0,
IPC_STAT,
arg);
assert(flag!=-1);
if(arg.buf->sem_otime!=0){
goto init;
}
sleep(1);
printf("semget OK, but semaphore not initialized");
exit(0);
}
}else{
printf("semget error");
}
init:
initflag = 1;
postop.sem_num = 0;
postop.sem_op = 1;
postop.sem_flg = SEM_UNDO;
waitop.sem_num = 0;
waitop.sem_op = -1;
waitop.sem_flg = SEM_UNDO;
}
flag=semop(semid,&waitop,1);
assert(flag!=-1);
}
void my_unlock(int fd)
{
int flag=semop(semid, &postop, 1);
assert(flag!=-1);
}