1.1 Posix信号灯-Semaphore
信号灯有以下两种类型:
二值信号灯:信号灯的值只能取0或1。
计算信号灯:信号灯的值可以取任意非负值。
每个信号灯都对应一个struct sem结构:
struct sem
{
unsigned shortint semval // 信号灯值
pid_t sempid // 上次对信号灯进行操作的进程id
unsigned shortint semzcnt // 等待信号灯值变为0的进程数目
unsigned shortint semncnt // 等待信号灯值变大的进程数目
}
1.1.1 信号灯的创建和删除
1.1.1.1 sem_open( )
#include<semaphore.h>
sem_t* sem_open( const char *name, int flag )
sem_t* sem_open( const char *name, int flag, mode_t mode, int value )
创建或获取named信号灯;成功返回信号灯的地址,失败返回SEM_FAILED((void*)-1)。
参数name指定与信号灯相关联的名字。
参数flag可以取O_CREAT、O_EXCL。
单独使用O_CREAT,如果不存在与name相关联的信号灯,就创建一个新的信号灯,并返回其地址,如果已经存在与name相关联的信号灯,就返回该信号灯的地址。
如果指定了O_CREAT,需要使用sem_open()的第二种形式,其中参数mode指定了新创建信号灯的访问权限,参数value指定了新创建信号灯的初始值。
单独使用O_EXCL是没有意义的,如果O_EXCL和O_CREAT一起使用,当与name相关联的信号灯已经存在时,就失败返回SEM_FAILED。
1.1.1.2 sem_init( )
#include<semaphore.h>
intsem_init( sem_t *sem, int pshared, unsigned int value )
创建一个unnamed信号灯。
参数value:信号灯的初值;
参数pshared:是否多进程共享(非0)或只用于一个进程(0)。
成功返回0,失败返回-1。
1.1.1.3 sem_close( )
#include <semaphore.h>
int sem_close( sem_t *sem )
只是用来表明当前进程不再使用一个named信号灯,该信号灯可以被删除。
1.1.1.4 sem_unlink( )
#include<semaphore.h>
intsem_unlink( const char *name )
删除一个named信号灯,但是如果当前仍有其它进程正在使用该信号灯,则暂时放弃删除操作,并立即返回,直到其它进程通过调用sem_close( )关闭之后,再进行删除操作。
成功返回0,失败返回-1。
1.1.1.5 sem_destroy( )
#include<semaphore.h>
int sem_destroy( sem_t *sem )
删除一个unnamed信号灯。
成功返回0,失败返回-1。
1.1.2 信号灯的操作
1.1.2.1 sem_getvalue( )
#include<semaphore.h>
int sem_getvalue(sem_t * sem, int * sval)
读取信号灯的值,由sval返回。如果信号灯正处于locked状态,则sval返回0或者一个负值,其绝对值表明正在等待该信号灯的进程的数目。
成功返回0,失败返回-1。
1.1.2.2 sem_post( )
#include<semaphore.h>
int sem_post( sem_t * sem )
将信号灯的值加1。
成功返回0,失败返回-1。
1.1.2.3 sem_wait( )
#include<semaphore.h>
int sem_wait( sem_t * sem )
如果信号灯值>0,将信号灯值减1,成功返回。
如果信号灯值≤0,等待信号灯值>0,然后将信号灯值减1,成功返回。
成功返回0,失败返回-1。
1.1.2.4 sem_trywait( )
#include <semaphore.h>
int sem_trywait( sem_t * sem )
如果信号灯值>0,将信号灯值减1,成功返回。
如果信号灯值≤0,立即失败返回。
成功返回0,失败返回-1。
1.2 系统V信号灯-Semaphore
1.2.1 ftok( )
#include<sys/types.h>
#include<sys/ipc.h>
key_tftok( const char *name, int id )
参数name指定了文件名(包含路径),该文件必须存在,而且当前进程必须能够访问该文件。
参数id只有低8位有效。
只有当name和id取值都相同时,返回的键值key才是相同的。
成功返回键值,失败返回-1。
1.2.2 semget( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
intsemget( key_t key, int nsems, int semflg )
创建或获取信号灯集;成功返回与key相关联的信号灯集id,失败返回-1。
参数nsems指定创建或获取的信号灯集中包含信号灯的数目。
参数semflg可以取IPC_CREAT、IPC_EXCL、IPC_NOWAIT。
单独使用IPC_CREAT,如果不存在与键值key相关联的信号灯集,就创建一个新的信号灯集,并返回其id,如果已经存在与键值key相关联的信号灯集,就返回该信号灯集id。
单独使用IPC_EXCL是没有意义的,如果IPC_EXCL和IPC_CREAT一起使用,当与键值key相关联的信号灯集已经存在时,就失败返回-1。
下面两种情况会创建一个新的信号灯集:
1.参数semflg指定IPC_CREAT,而且没有信号灯集与键值key相关联;
2.参数key指定IPC_PRIVATE;
参数semflg的低9位指定新创建信号灯集的访问权限:
所有者 | 组成员 | 其他成员 | ||||||
读 | 写 | 执行 | 读 | 写 | 执行 | 读 | 写 | 执行 |
1.2.3 semop( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
intsemop( int semid, struct sembuf * sops, unsigned nsops )
#include<time.h>
intsemtimedop( int semid, struct sembuf *sops, unsigned nsops, struct timespec*timeout )
参数sops指定了一组操作,用一个数组表示。
参数nsops指定了操作的数目,也就是数组的大小。
struct sembuf
{
unsigned short sem_num; /*semaphore index in array,0对应第一个信号灯*/
short sem_op; /*semaphore operation */
short sem_flg; /* operation flags */
};
sem_flg可取:IPC_NOWAIT或SEM_UNDO(进程结束时,对信号灯集进行undo操作)。
sem_op指定了三种操作:
1.如果sem_op>0,信号灯值加上sem_op,成功返回。
2.如果sem_op = 0:
1.信号灯值为0,成功返回;
2.信号灯值不为0而且sem_flg设置了IPC_NOWAIT,失败返回;
3.信号灯值不为0而且sem_flg未设置IPC_NOWAIT,挂起当前进程直到发生:
1.信号灯值变为0,成功返回;
2.信号灯所在的信号灯集被删除,失败返回;
3.等待超时,失败返回。
3.如果sem_op<0:
1.信号灯值≥abs(sem_op),信号灯值减去abs(sem_op),成功返回;
2.信号灯值<abs(sem_op)而且sem_flg设置了IPC_NOWAIT,失败返回;
3.信号灯值<abs(sem_op)而且sem_flg未设置IPC_NOWAIT,挂起当前进程直到发生:
1.信号灯值≥abs(sem_op),信号灯值减去abs(sem_op),成功返回;
2.信号灯所在的信号灯集被删除,失败返回;
3.等待超时,失败返回。
注意:Linux保证所有操作的原子性,也就是说要么完成所有操作成功返回,要么什么操作都不做失败返回。成功返回0,失败返回-1。
1.2.4 semctl( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
intsemctl( int semid, int semnum, int cmd/, union semun arg / )
获取或设置信号灯集的属性,参数semid指定信号灯集,参数semnum指定信号灯。
参数arg用于设置或返回信号灯集的信息,只对某些cmd操作有意义。
union semun
{
int val;
struct semid_ds * buf;
unsigned short * array;
};
参数cmd指定具体的操作类型;
IPC_RMID 删除信号灯集
IPC_STAT 获取信号灯集的信息,由arg.buf返回
IPC_SET 设置信号灯集的信息,由arg.buf设置
GETALL 获取所有信号灯的值,由arg.array返回
SETALL 设置所有信号灯的值,由arg.array设置
SETVAL 设置semnum信号灯的值,由arg.val设置
GETVAL 返回semnum信号灯的值
GETPID 返回semnum信号灯的sempid
GETNCNT 返回semnum信号灯的semncnt
GETZCNT 返回semnum信号灯的semzcnt
成功返回0或对应值,失败返回-1。