信号量不是IPC机构,它只是一个计数器用于不同进程之间或同一进程不同线程之间的同步,类型:二元信号:值为0或1,1说明有可用资源,0说明此时资源占用,其他进程需等待。计数信号量:表示可用资源数量。计数信号量集:由一个或多个信号量组成的集合,每一个都是计数信号量。
信号量数据结构:
#include <sys/sem.h>
struct semid_ds // 信号量描述符{
struct ipc_perm sem_perm; // 操作权限结构体
struct sem * sem_base; // 信号量指针
ushort sem_nsems; // 信号量数量
time_t sem_otime; // 最近一次操作的时间
time_t sem_ctime; // 上一次修改时间
};
#include <sys/ipc.h>
struct ipc_perm //权限设置结构体
{
uid_t uid; // 所有者用户ID
gid_t gid; // 所有者组ID
uid_t cuid; // 创建者ID
gid_t cgid; // 创建者组ID
mode_t mode; // 读写权限
ulong_t seq; // 槽的使用序列号
key_t key; // IPC键
};
struct sem {
ushort_t semval; // 信号值,非负
short sempid; // 上一次对其进行成功操作的进程PID
ushort_t semncnt; // 等待semval增加(长)的进程数
ushort_t semzcnt; // 等待semval=0(为0)的进程数
}
信号的创建和操作:
#include<sys/types.h>
#incldue<sys/ipc.h>
#include<sys/sem.h>
int semget (key_t key , int nsems , int flag)
获取一个信号量集,key是一个键值由ftok获得,nsems:信号量集合中信号个数,flag读写标志位。
int semop(int semid , struct sembuf *opsptr , size_t nops)
对创建好的信号量集操作,参数struct sembuf {
short sem_num; //信号编号
short sem_op; //信号操作
short sem_flag; //信号标志
};
opsptr指向数组的每一个sembuf表示一个特定信号量的操作,nops标志指向数组大小。
当sem_op为正时,进程释放占用资源,sem_op值加到信号量值。
当sem_op为负,获取该信号量控制资源,在信号量值小于sem_op绝对值(资源不满足要求),则:若指定IPC_NOWAIT,则semop出错返回EAGAIN。若未指定IPC_NOWAIT调用进程进入休眠状态,直到:某些进程释放资源;系统删除该信号量;进程捕捉一个信号。
当semop为0,表示调用进程希望等到该信号量值变为0,信号量值是0立即返回,非0时,若指定IPC_NOWAIT,则出错返回,若未指定进程休眠情况同上。
int semctl (int semid , int semnum , int cmd, ....../*union semun arg*/)
实现对信号量各种控制操作,semid:要进行操作的信号量集,senum:信号集中的某个信号量可取为GETVAL,SETVAL,GETNCNT,GETPID。最后一个参数可选取决于第三个参数cmd,union senum {
int val ; // for SETVAL
struct semid_ds *buf ; //for IPC_SET and IPC_STAT
ushort *array //for GETALL and SETALL
}
cmd取值,在semid指定信号集合执行此命令,
IPC_STAT:取信号集的semid_ds结构,并存放arg.buf结构。
IPC_SET:按照arg.buf指向结构中的值,设置此信号集的三个字段,即sem_perm结构体的uid,gid,mode。
IPC_RMID:从系统中删除该信号量集合。
GETVAL:返回成员semnum的semval值。
SETVAL:设置semnum的semval值,该值由arg.val指定。
GETPID:返回semnum的sempid.
GETNCNT:返回semnum的semncnt值
GETZCNT:返回semnum的semzcnt值
GETALL:取信号所有值放入array中。
SETALL:按照array每一个值设置集合中的每个信号量的值。