信号量(semaphore)
进程间通信-信号量
1、为什么要使用信号量
为了防止多个程序同时访问一个共享资源而引发的一系列问题,故有这样一种方法,在任何一个时刻只有一个执行线程访问代码的临界区(临界区是指访问临界资源的代码),而信号量就可以提供这样的访问机制,同一时刻只允许一个线程访问临界区,也就是说信号量是用来协调进程共享资源访问的,也就是说信号量用来协调进程对共享资源访问的,其中共享内存就是用信号量实现的。
2、信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,他们是p(sv)操作,v(sv)操作。
p(sv)操作:如果sv的值大于0.他就减1,如果sv的值等于0,它就挂起进程的执行。
v(sv)操作:如果有其他进程因等待sv而挂起,则就让他恢复运行,如果没有进程因等待它而挂起,就让他加1.
举个例子,就是 两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为 当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。
3、Linux信号量机制
Linux提供了一组精心设置的信号量接口来对信号量进行操作。这些函数都是用来对组的信号量进行操作,他们被声明在sys/sem.h中。
4、信号量的使用
(1)创建信号量
semget函数创建一个信号量集或者访问一个已存在的信号量集
intsemget(key_tkey,intnsem,intoflag)
返回值是一个称为信号量标识符的整数,semop和semctl函数将使用它。成功返回信号量的标示符,失败返回-1
key:由ftok()函数得到,
nsem:创建信号量中的个数
oflag:
IPC_CREAT:若内核中不存在键值与key相等的信号量集,则创建,否则,返回此信号量集的标识符
IPC_EXCL:单独使用无意义
IPC_CREAT | IPC_EXCL :创建一个新的信号量集并返回信号量集的标识符,否则,返回-1.
(2)打开信号量(完成对信号量的PV操作)
用semget打开一个信号量后,对其中一个或多个信号量操作就是用semop来执行。
intsemop(intsemid,structsembuf*opsptr,size_tnops)
semid:信号量集标识符
nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1.
opspt:是一个指针,它指向一个信号量操作数组,信号量操作由sembuf结构表示
structsembuf{shortsem_num;//除非使用一组信号量,否则它为0shortsem_op;//信号量在一次操作中需要改变的数据,通常是两个数,//一个是-1,即P(等待)操作,一个是+1,即V(发送信号)操作shortsem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,//操作系统释放信号量};
当操作信号量(semop)时,flg可以设置SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常、除0异常、收到KILL信号等)时归还给信号量。进程以SEM_UNDO方式操作后;在进程未退出时,可以改变信号量的值,在进程退出时,将修改的值归还给信号量,信号量变成原来的值。
(3)在指定信号集或者信号集上的某个信号进行操作
intsemctl(intsemid,intsemnum,intcmd,unionsemunarg)
semid: 信号量集标识符
semnum:信号量集数组上的下标,表示某一个信号量
第四个参数是可选的,取决于第个信号(操作对象)
参数cmd指定以下10种命令中的一种,在semid指定的信号量集合上执行此命令。
IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET 设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID 将信号量集从内存中删除。
GETALL 用于读取信号量集中的所有信号量的值。
GETNCNT 返回正在等待资源的进程数目。
GETPID 返回最后一个执行semop操作的进程的PID。
GETVAL 返回信号量集中的一个单个的信号量的值。
GETZCNT 返回这在等待完全空闲的资源的进程数目。
SETALL 设置信号量集中的所有的信号量的值。
SETVAL 设置信号量集中的一个单独的信号量的值。
5.例子
comm.h
#define_PATH_NAME_"/tmp"#define_PROJ_ID_0x6666intcreate_sem_set();unionsemun{intval;structsemid_ds*buf;unsignedshort*array;structeminfo*_buf;};intinit_sem_set(intsem_id,intwhich,intval);intcreate_sem_set(intnums);intget_sem_set();intdestory_sem_set(intsem_id);intP(intsem_id,intnum);intV(intsem_id,intnum);
comm.c
#include"comm.h"staticintcomm_sem_set(intnums,intflags){key_t_key=ftok(_PATH_NAME_,_PROJ_ID_);if(_key<0){perror("ftok");return-1;}//intsem_id=semget(_key,nums,IPC_CREAT|IPC_EXCL);intsem_id=semget(_key,nums,flags);if(sem_id<0){perror("semget");return-2;}returnsem_id;}intcreate_sem_set(intnums){intflags=IPC_CREAT|IPC_EXCL|0666;returncomm_sem_set(nums,flags);}intget_sem_set(){intflags=IPC_CREAT;returncomm_sem_set(0,flags);}intdestory_sem_set(intsem_id){if(semctl(sem_id,0,IPC_RMID)<0){perror("semctl");}return0;}intinit_sem_set(intsem_id,intwhich,intval){unionsemun_un;_un.val=val;if(semctl(sem_id,which,SETVAL,_un)<0){perror("semctl");return-1;}}staticintcomm_op(intsem_id,intnum,intop){structsembuf_sembuf;_sembuf.sem_num=num;_sembuf.sem_op=op;_sembuf.sem_flg=0;if(semop(sem_id,&_sembuf,1)<0){perror("semop");return-1;}return0;}intP(intsem_id,intnum){intop=-1;returncomm_op(sem_id,num,op);}intV(intsem_id,intnum){intop=-1;returncomm_op(sem_id,num,op);}
test_sem.c
#include<stdio.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#define_PATH_NAME_"/tmp"#define_PROJ_ID_0x6666intcreate_sem_set();unionsemun{intval;structsemid_ds*buf;unsignedshort*array;structeminfo*_buf;};intinit_sem_set(intsem_id,intwhich,intval);intcreate_sem_set(intnums);intget_sem_set();intdestory_sem_set(intsem_id);intP(intsem_id,intnum);intV(intsem_id,intnum);[lh@localhostSEM]$^C[lh@localhostSEM]$catcomm.c#include"comm.h"staticintcomm_sem_set(intnums,intflags){key_t_key=ftok(_PATH_NAME_,_PROJ_ID_);if(_key<0){perror("ftok");return-1;}//intsem_id=semget(_key,nums,IPC_CREAT|IPC_EXCL);intsem_id=semget(_key,nums,flags);if(sem_id<0){perror("semget");return-2;}returnsem_id;}intcreate_sem_set(intnums){intflags=IPC_CREAT|IPC_EXCL|0666;returncomm_sem_set(nums,flags);}intget_sem_set(){intflags=IPC_CREAT;returncomm_sem_set(0,flags);}intdestory_sem_set(intsem_id){if(semctl(sem_id,0,IPC_RMID)<0){perror("semctl");}return0;}intinit_sem_set(intsem_id,intwhich,intval){unionsemun_un;_un.val=val;if(semctl(sem_id,which,SETVAL,_un)<0){perror("semctl");return-1;}}staticintcomm_op(intsem_id,intnum,intop){structsembuf_sembuf;_sembuf.sem_num=num;_sembuf.sem_op=op;_sembuf.sem_flg=0;if(semop(sem_id,&_sembuf,1)<0){perror("semop");return-1;}return0;}intP(intsem_id,intnum){intop=-1;returncomm_op(sem_id,num,op);}intV(intsem_id,intnum){intop=-1;returncomm_op(sem_id,num,op);}[lh@localhostSEM]$^C[lh@localhostSEM]$clear[lh@localhostSEM]$cattest_sem.c#include"comm.h"#include<stdio.h>intmain(){intsem_id=create_sem_set(1);pid_tid=fork();init_sem_set(sem_id,0,1);if(id==0){intsem_id_child=get_sem_set();while(1){P(sem_id_child,0);printf("A");fflush(stdout);usleep(rand()%3);printf("A");fflush(stdout);usleep(rand()%12345);V(sem_id_child,0);}}else{while(1){P(sem_id,0);printf("B");fflush(stdout);usleep(rand()%3);printf("B");fflush(stdout);usleep(rand()%12234);V(sem_id,0);}wait(NULL);destory_sem_set(sem_id);}return0;}
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。