进程间通信-信号量
来源:互联网 发布:java 读取远程文件 编辑:程序博客网 时间:2024/05/29 14:35
1.1. 信号量
信号量是一个内核变量,可以被任意进程访问
sv是一个信号变量
P(sv)等待,如果sv大于0,减小sv。如果sv为0,挂起这个进程的执行。
V(sv)唤醒信号,如果有进程被挂起等待sv,使其恢复执行。如果没有进行被挂起等待sv,增加sv。
#include<sys/sem.h>
(1) int semget(key_t key, intnum_sems, int sem_flags);
l 第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为不同的程序通过提供一个key来间接访问的,对于每一个信号量系统 生成一个信号量标识符。
l num_sems参数是所需要的信号量数目。这个值通常总是1。
l sem_flags参数是一个标记集合,与open函数的标记十分类似。低九位是信号的权限,其作用与文件权限类似。另外,这些标记可以与IPC_CREAT进行或操作来创建新的信号量。设置IPC_CREAT标记并且指定一个已经存在的信号量键值并不是一个错误。如果不需 要,IPC_CREAT标记只是被简单的忽略。我们可以使用IPC_CREAT与IPC_EXCL的组合来保证我们可以获得一个新的,唯一的信号量。如果 这个信号量已经存在,则会返回一个错误。
l return:如果成功,semget函数会返回一个正数;这是用于其他信号量函数的标识符。如果失败,则会返回-1。
#define SEM_KEY 1111
int sem_id =semget(SEM_KEY,2,0666|IPC_CREAT|IPC_EXCL);
//创建信号量集,且是唯一的新的
(2) int semop(int sem_id, structsembuf *sem_ops, size_t num_sem_ops); 函数semop用来改变信号量的值
l 第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
l 第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。
l sem_op成员是信号量的变化量值。(我们可以以任何量改变信 号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。
l 最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量, 如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行 为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清 理我们的信号量。
int sem_id =semget(SEM_KEY,2,0666|IPC_CREAT|IPC_EXCL);
struct sembufactions[2]; //0代表reader,1是wirter
actions[0]. sem_num = 0;
actions[0]. sem_op =0;//等待,直到没有reader
actions[0]. sem_flg = SEM_UNDO;
actions[1]. sem_num = 0;
actions[1]. sem_op =+1;//增加wirter的数目
actions[1]. sem_flg = SEM_UNDO;
semop(semid, actions,2);
(3) int semctl(int sem_id, intsem_num, int command, ...); semctl函数允许信号量信息的直接控制
l 第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果 这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是union semun,根据X/OPEN规范,这个参数至少包括下列参数:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}
许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需 要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。
有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。
l 这两个通常的command值为:SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。IPC_RMID:当信号量不再需要时用于删除一个信号量标识。
l semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。
union semun init;
init.value = val;
semctl(semset_id,0,SETVAL, init)//设置值
semctl(semset_id, 0,IPC_RMID, 0)//删除信号量
例子:
服务器:
#include<sys/sem.h>
int seg_id,semset_id;
#define TIME_MEM_KEY 99
#define TIME_SEG_KEY9999
#def SEG_SIZE 100
#def oops(x,y){ perror(x);exit(y);}
void set_mem_value(intsemid,int sum_num,value){
union semun init;
init.value = value;
if(semctl(semid, sum_num,SETVAL, init)){
oops(“semctl”,9);
}
}
void wait_and_lock(intsemset_id){
struct sembuf actions[2]; //0代表reader,1是wirter
actions[0]. sem_num = 0;
actions[0]. sem_op =0;//等待,直到没有reader
actions[0]. sem_flg = SEM_UNDO;
actions[1]. sem_num = 0;
actions[1]. sem_op =+1;//增加wirter的数目
actions[1]. sem_flg = SEM_UNDO;
if(semop(semid, actions,2)==-1){
oops(“semop”,9);
}
}
void release_lock(intsemset_id){
struct sembuf actions[1];
actions[0]. sem_num = 1;
actions[0]. sem_op = -1;// 减少wirter的数目
actions[0]. sem_flg = SEM_UNDO;
if(semop(semid, actions,1)==-1){
oops(“semop”,10);
}
}
void main(){
char *pmem = NULL,*pctime;
time_t now;
/*分配共享内存*/
seg_id = shmget(TIME_MEM_KEY,SEG_SIZE,IPC_CREAT|0777);
if(seg_id<0){
oops(“shmget”,1);
}
pmem = shmat(seg_id,NULL,0);
if(pmem==NULL){
oops(“shmat”,2);
}
/*获取信号量集*/
semset_id =segget(TIME_SEG_KEY,2,0666| IPC_CREAT|IPC_EXCL);
if(semset_id == -1){
oops(“segget”,3);
}
set_mem_value(semset_id,0,0);
set_mem_value(semset_id,1,0);
signal(SIGINT,cleanup);/*收到信号SIGINT时的处理函数是cleanup */
while(1){
time(&now);
wait_and_lock(semset_id);/*读挂起,写打开*/
strcpy(pmem,ctime(&now));
}
}
/*客户端程序*/
void wait_and_lock(int semset_id){
structsembuf actions[2]; //0代表reader,1是wirter
actions[0].sem_num = 1;
actions[0].sem_op =0;//等待,直到没有wirter
actions[0].sem_flg = SEM_UNDO;
actions[1].sem_num = 0;
actions[1].sem_op = +1;//增加reader的数目
actions[1].sem_flg = SEM_UNDO;
if(semop(semid,actions,2)==-1){
oops(“semop”,9);
}
}
void release_lock(int semset_id){
structsembuf actions[1];
actions[0].sem_num = 0;
actions[0].sem_op = -1;// 减少reader的数目
actions[0].sem_flg = SEM_UNDO;
if(semop(semid,actions,1)==-1){
oops(“semop”,10);
}
}
void main(){
char *pmem = NULL,*pctime;
time_t now;int semset_id;
seg_id = shmget(TIME_MEM_KEY,SEG_SIZE,IPC_CREAT|0777);
if(seg_id<0){
oops(“shmget”,1);
}
pmem = shmat(seg_id,NULL,0);
if(pmem==NULL){
oops(“shmat”,2);
}
semset_id = segget(TIME_SEG_KEY,2,0);
if(semset_id == -1){
oops(“segget”,3);
}
wait_and_lock(semset_id);
printf(“%s”,pmem);
release_lock(semset_id);
shmdt(pmem);
}
- 进程间通信 信号量
- 进程间通信--信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 【进程间通信】信号量
- 进程间通信----信号量
- 进程间通信:信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 进程间通信--信号量
- 进程间通信---->信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 进程间通信----信号量
- 进程间通信-信号量
- 第003课 进制的算术运算(2)
- 关于JSP页面中的pageEncoding和contentType两种属性的区别 servlet 乱码
- android布局属性详解
- java表达式类型的自动提升
- hibernate主键生成策略设置不当导致的错误
- 进程间通信-信号量
- 获取系统的一些信息汇总
- 编写自己的jquery插件
- SMTP error: could not connet to smtp host
- [oracle]oifcfg命令详解
- What Does The HANDLECOLLISIONS Parameter Do? [ID 966207.1]
- C++ 继承中子类与父类虚函数入栈顺序 及父类私有虚函数的调用方式
- cocos2d-x CCDirector管理CCScene
- MapReduce 详解