同共享内存一样,系统中同样需要为信号量集定制一系列专有的操作函数(semget,semctl等)。系统命令ipcs可查看当前的系统IPC的状态,在命令后使用-s参数。使用函数semget可以创建或者获得一个信号量集ID,函数原型如下:
#include <sys/shm.h>
int semget( key_t key, int nsems, int flag)
函数中参数key用来变换成一个标识符,每一个IPC对象与一个key相对应。当新建一个共享内存段时,使用参数flag的相应权限位对ipc_perm结构中的mode域赋值,对相应信号量集的shmid_ds初始化的值如表1所示。
shmid_ds结构初始化值表 ipc_perm结构数据 初 值 ipc_perm结构数据 初 值 Sem_otime 0 Sem_nsems Nsems Sem_ctime 系统当前值 参数nsems是一个大于等于0的值,用于指明该信号量集中可用资源数(在创建一个信号量时)。当打开一个已存在的信号量集时该参数值为0。函数执行成功,则返回信号量集的标识符(一个大于等于0的整数),失败,则返回–1。函数semop用以操作一个信号量集,函数原型如下:
#include <sys/sem.h>
int semop( int semid, struct sembuf semoparray[], size_t nops )
函数中参数semid是一个通过semget函数返回的一个信号量标识符,参数nops标明了参数semoparray所指向数组中的元素个数。参数semoparray是一个struct sembuf结构类型的数组指针,结构sembuf来说明所要执行的操作,其定义如下:
struct sembuf{
unsigned short sem_num
short sem_op
short sem_flg
}
在sembuf结构中,sem_num是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。sem_op指明所要执行的操作,sem_flg说明函数semop的行为。sem_op的值是一个整数,如表2所示,列出了详细sem_op的值及所对应的操作。
sem_op值详解 Sem_op 操 作 正数 释放相应的资源数,将sem_op的值加到信号量的值上 0 进程阻塞直到信号量的相应值为0,当信号量已经为0,函数立即返回。如果信号量的值不为0,则依据sem_flg的IPC_NOWAIT位决定函数动作。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生。信号量值为0,将信号量的semzcnt的值减1,函数semop成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM;进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR 负数 请求sem_op的绝对值的资源。如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。当相应的资源数不能满足请求时,这个操作与sem_flg有关。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:当相应的资源数可以满足请求,该信号的值减去sem_op的绝对值。成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM:进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR
信号量:一个整数;大于或等于0时代表可供并发进程使用的资源实体数;
小于0时代表正在等待使用临界区的进程数;
用于互斥的信号量初始值应大于0;
只能通过P、V原语操作而改变;
信号量元素组成:
1、表示信号量元素的值;
2、最后操作信号量元素的进程ID
3、等待信号量元素值+1的进程数;
4、等待信号量元素值为0的进程数;
二、主要函数
1.1 创建信号量
int semget(
key_t key, //标识信号量的关键字,有三种方法:1、使用IPC——PRIVATE让系统产生,
// 2、挑选一个随机数,3、使用ftok从文件路径名中产生
int nSemes, //信号量集中元素个数
int flag //IPC_CREAT;IPC_EXCL 只有在信号量集不存在时创建
)
成功:返回信号量句柄
失败:返回-1
1.2 使用ftok函数根据文件路径名产生一个关键字
key_t ftok(const char *pathname,int proj_id)
路径名称必须有相应权限
1.3 控制信号量
int semctl(
int semid, //信号量集的句柄
int semnum, //信号量集的元素数
int cmd, //命令
/*union senum arg */... //
)
成功:返回相应的值
失败:返回-1
命令详细说明:
cmd: IPC_RMID 删除一个信号量
IPC_EXCL 只有在信号量集不存在时创建
IPC_SET 设置信号量的许可权
SETVAL 设置指定信号量的元素的值为 agc.val
GETVAL 获得一个指定信号量的值
GETPID 获得最后操纵此元素的最后进程ID
GETNCNT 获得等待元素变为1的进程数
GETZCNT 获得等待元素变为0的进程数
union senum 定义如下:
union senum{
int val
struct semid_ds *buf
unsigned short * array
}agc
其中 semid_ds 定义如下:
struct semid_ds{
struct ipc_pem sem_pem //operation pemission struct
time_t sem_otime //last semop()time
time_t sem_ctime //last time changed by semctl()
struct sem *sembase //ptr to first semaphore in array
struct sem_queue *sem_pending//pending operations
struct sem_queue *sem_pending_last//last pending operations
struct sem_undo *undo //undo requests on this arrary
unsigned short int sem_nsems//number of semaphores in set
}
1.4 对信号量 +1 或 -1 或测试是否为0
int semop(
int semid,
struct sembuf *sops, //指向元素操作数组
unsigned short nsops //数组中元素操作的个数
)
结构 sembuf 定义
sembuf{
short int sem_num//semaphore number
short int sem_op//semaphore operaion
short int sem_flg //operation flag
}
三、例子:
2.1 服务器
#include <sys/sem.h>
#include <sys/ipc.h>
#define SEGSIZE 1024
#define READTIME 1
union semun {
int val
struct semid_ds *buf
unsigned short *array
} arg
//生成信号量
int sem_creat(key_t key)
{
union semun sem
int semid
sem.val = 0
semid = semget(key,1,IPC_CREAT|0666)
if (-1 == semid){
printf("create semaphore error\n")
exit(-1)
}
semctl(semid,0,SETVAL,sem)
return semid
}
//删除信号量
void del_sem(int semid)
{
union semun sem
sem.val = 0
semctl(semid,0,IPC_RMID,sem)
}
//p
int p(int semid)
{
struct sembuf sops={0,+1,IPC_NOWAIT}
return (semop(semid,&sops,1))
}
//v
int v(int semid)
{
struct sembuf sops={0,-1,IPC_NOWAIT}
return (semop(semid,&sops,1))
}
int main()
{
key_t key
int shmid,semid
char *shm
char msg[7] = "-data-"
char i
struct semid_ds buf
key = ftok("/",0)
shmid = shmget(key,SEGSIZE,IPC_CREAT|0604)
if (-1 == shmid){
printf(" create shared memory error\n")
return -1
}
shm = (char *)shmat(shmid,0,0)
if (-1 == (int)shm){
printf(" attach shared memory error\n")
return -1
}
semid = sem_creat(key)
for (i = 0i <= 3i++){
sleep(1)
p(semid)
sleep(READTIME)
msg[5] = '0' + i
memcpy(shm,msg,sizeof(msg))
sleep(58)
v(semid)
}
shmdt(shm)
shmctl(shmid,IPC_RMID,&buf)
del_sem(semid)
return 0
//gcc -o shm shm.c -g
}
2.2 客户端
#include <sys/sem.h>
#include <time.h>
#include <sys/ipc.h>
#define SEGSIZE 1024
#define READTIME 1
union semun {
int val
struct semid_ds *buf
unsigned short *array
} arg
// 打印程序执行时间
void out_time(void)
{
static long start = 0
time_t tm
if (0 == start){
tm = time(NULL)
start = (long)tm
printf(" now start ...\n")
}
printf(" second: %ld \n",(long)(time(NULL)) - start)
}
//创建信号量
int new_sem(key_t key)
{
union semun sem
int semid
sem.val = 0
semid = semget(key,0,0)
if (-1 == semid){
printf("create semaphore error\n")
exit(-1)
}
return semid
}
//等待信号量变成0
void wait_v(int semid)
{
struct sembuf sops={0,0,0}
semop(semid,&sops,1)
}
int main(void)
{
key_t key
int shmid,semid
char *shm
char msg[100]
char i
key = ftok("/",0)
shmid = shmget(key,SEGSIZE,0)
if(-1 == shmid){
printf(" create shared memory error\n")
return -1
}
shm = (char *)shmat(shmid,0,0)
if (-1 == (int)shm){
printf(" attach shared memory error\n")
return -1
}
semid = new_sem(key)
for (i = 0i <3i ++){
sleep(2)
wait_v(semid)
printf("Message geted is: %s \n",shm + 1)
out_time()
}
shmdt(shm)
return 0
// gcc -o shmc shmC.c -g
}
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)