###################################################
信号量
信号量:在多线程环境下,用来保证多个关键代码不被并发调用,一次只能有个一个线程访问关键代码。
信号量有两组函数接口:
1.posix信号量
2.system v信号量
信号量的两种形式:
1.二进制信号量:用来保护一段代码,使其每次只能被一个执行线程运行,初始值一般为1.
2.计数信号量:有限数目的线程执行一段指定的代码,初始值一般大于1.
-----------------------------------------------------------
posix信号量:
posix信号量分两种:
1.posix有名信号量,一般用在无亲缘关系的进程间。
2.posix基于内存的信号量(无名信号量),一般用在不需要使用与有名信号量关联的名字。
gcc - lpthread
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
sem_t *sem_open(const char*name, int oflag);
打开一个已存在的有名信号量。
sem_t *sem_open(const char*name, int oflag, mode_t mode, unsigned int value);
创建一个有名信号量。
value:信号量初始值。
int
sem_close(sem_t *sem);
关闭有名信号量
int
sem_unlink(const char*name);
删除有名信号量
int
sem_init(sem_t *sem, int pshared, unsigned int value);
初始化无名(基于内存)信号量;
pshared:
0:信号量在同一个进程间的线程间共享
非0:在进程间共享信号量
value:信号量的初始值
int
sem_destroy(sem_t *sem);
销毁无名(基于内存)信号量
信号量等待操作,在使用信号量之前调用:
int
sem_wait(sem_t *sem);
如果信号量值大于0,就减去1然后返回,如果信号量值等于0,就阻塞。
int sem_trywait(sem_t *sem);
等待操作的非阻塞版本,如果信号量值等于0,立即返回错误。
int sem_timedwait(sem_t *sem, conststruct timespec *abs_timeout);
阻塞指定的时间。
信号量挂出操作,在使用信号量之后调用
int
sem_post(sem_t *sem);
将信号量的值加1.
获取信号量的值
int
sem_getvalue(sem_t *sem,int *sval);
返回信号量的当前值放入sval中,如果信号量已上锁返回0或某个负数,负数的绝对值表示等待该信号量解锁的进程数。
SEM_NSEMS_MAX:一个进程可以同时打开的最大信号量数目。
SME_VALUE_MAX:一个信号量的最大值。
-----------------------------------------------------------
system v信号量:
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
内核位system V维护一个信号量结构:
struct semid_ds {
struct ipc_permsem_perm;
struct sem*sem_base;//指向信号量集
ushort sem_nsems;//初始化为nsems
time_t sem_otime;//初始化为0
time_t sem_ctime;//初始化为当前时间
}
struct sem {
ushort_t semval; //信号量的值
short sempid; //对semval值进行最后一次操作的进程ID
ushort_t semncnt;//等待semval变为大于其当前值的线程数。
ushort_t semzcnt;//等待semval变为0的线程数。
}
int semget(key_t key, int nsems, int semflg);
创建一个信号量集或访问一个已存在的信号量集,返回信号量标识符。
key:既可以是ftok的返回值,也可以是IPC_PRIVATE.
nsems:
指定集合中的信号量数,访问一个已存在信号量就置0.
semflg:
semflg: 可以用读写权限 或 其它可选权限。
0:打开已存在的
属主:SEM_R SEM_A
属组:SEM_R >> 3 SEM_A >> 3
其它:SEM_R >> 6 SEM_A >> 6
IPC_CREAT:不存在就创建,存在就返回已存在的。
IPC_CREAT | IPC_EXCL:不存在就创建,存在就返回错误。
int semop(int semid, struct sembuf *sops, unsignednsops);
对信号量的操作,sops指向一个结构数组,nsops是数组元素个数。
struct sembuf {
unsigned shortsem_num; //0-nsems 指定某个信号量
short sem_op;
short sem_flg;
};
sem_op: 决定做什么操作
0:等待semval变为0
1(正数):将该值加到semval上,如果semval已经为0,就返回。
-1(负数):等待semval变为大于或等于该值的绝对值。
sem_flg:
IPC_NOWAIT:给定信号量非阻塞
SEM_UNDO:指定该标识,semadj才会更新,
int semctl(int semid, int semnum, int cmd, (union semunarg …);
对一个信号量执行各种控制操作,semnum为0-nsems 为指定的某个信号量。
第四个参数由第三个参数决定,这个结构需要自己定义:
union semun {
int val;//SETVAL
struct semid_ds*buf;//IPC_SET IPC_STAT
ushort*array;//GETALL SETALL
} arg;
cmd:命令执行成功函数返回0,失败函数返回-1:
GETVAL:获取semval的值返回
GETPID:把sempid的当前值作为函数返回值
GETNCNT:把semncnt的当前值作为函数返回值
GETZCNT:把semzcnt的当前值作为函数返回值
IPC_RMID:把semid指定的信号量集从系统中删除
cmd取下列值才有第四个参数arg:
GETALL:通过arg.array返回指定信号量集内每个成员的semval。
SETALL:将arg.array中的值赋给信号量集中的每个semval。
SETVAL:将arg.val的值赋给semval。
IPC_STAT:通过arg.buf获取指定信号量集中当前semid_ds结构。
IPC_SET:用arg.buf设置指定信号集中semid_ds结构中的ipc_perm结构的三个成员。