本文主要是介绍【进程间通信】------信号量(sems),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一直想看看ftok函数,今天就在这里进行简单的介绍下
ftok()函数我们在进行IPC通讯的时候必须指定一个ID值,这个值通常情况下就是由ftok进行提供。
ftok原型如下:
key_t ftok( char * fname, int id )
参数说明:
fname就时您指定的文档名
id是子序号。
返回值:
在一般的UNIX实现中,是将文档的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文档的索引节点号为65538,换算成16进制为0x010002,而您指定的ID值为38,换算成16进制 为 0x26,则最后的key_t返回值为0x26010002。
认识信号量
信号量主要用于同步和互斥的,信号量的本质是一个计数器,信号量记录了临界资源的数目,数目为多少,信号量的数目就为多少,信号量的值为1的称为二元信号量(也成二元信号量称为互斥锁)。信号量的生命周期随内核。
进程互斥
- 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥。
- 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
在进程中涉及到互斥资源的程序叫做临界区
进程同步指的是多个进程需要相互配合共同完成一项任务。
信号量和P,V原语(p、v操作是原子的,要么做了,要么没做,无中间态产生。`信号量和P、V原语由Dijkstra(迪杰斯特拉)提出的
- 信号量
互斥:P、V在同一个进程中
同步: P、V不在同一个进程当中
信号量的含义:
s>0:s表示的是可用资源的数目
s=0:表示无可用资源,无等待进程
s<0:|s|表示等待队列中的进程个数
信号量结构体伪代码
信号量本质上是一个计数器
struct semaphore
{int value;point_PCB queue;
}
p原语
p(s)
{
s.value=s.value–;
if(s.value<0)
{
该进程状态置为等待状状态
该进程的PCB插入到相应的等待队列s.queue末尾
}
}
v原语
v(s)
{
s.value=s.value++;
if(s.value>=0)
{
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪态
并将其插入就绪队列
}
}
信号量集函数
semget函数
功能:用来创建和访问一个信号量集
原型:
int semget(key_t key,int nsems,int semflgs);
参数:
key:信号量集的名字
nsems:信号量集中信号量的个数
semflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值;成功返回一个非负整数,即该信号即的标识码,失败返回的是-1
shmctl函数
功能:用于控制信号量集
原型:
int semctl(int semid,int semnum,int cmd,….)
参数:
semid:由semget返回的信号集标识码
semnum:信号集中信号量的编号
cmd:将来采取的动作(有三个可能值)
最后一个参数根据命令的不同而不同
返回值:成功返回的是0,失败返回的是-1
命令 | 说明 |
---|---|
SETVAL | 设置信号量集中的信号量的计数值 |
GETVAL | 获取信号量集中的信号量的计数值 |
IPC_STAT | 把semid_ds结构中的数据设置为信号量集的当前关联值 |
IPC_SET | 在进程有足够权限前提下,把信号量集的当前关联值设置为semid_ds数据结构中的值 |
IPC_RMID | 删除信号集 |
semop函数
用来创建和访问一个信号量集
原型:
int semop(int semid ,struct sembuf *sops,unsigned nsops);
参数:
semid:是该信号量的标识码,也是semget函数的返回值
sops:是个指向一个结构数值的指针
nsops:信号量的个数
返回值:成功返回,失败返回-1
sembuf 结构体:
struct sembuf{short sem_num;short sem_op;short sem_flag;};
sem_num是信号量的编号。
sem_op是信号量一次pv操作时加减的数值,一般只会用到两个值:
一个是“-1“,也就是进行的是p操作,等待信号量变为可用
一个是“+1”,也就是我们进行的v操作,发出信号量已经变得可用
sem_flag两个取值是IPC_NOWAIT或SEM_UNDO
实例代码:
两个进程同时进行打印,显示器为临界资源,使用二元信号量(互斥锁)进行保护。
代码实现:
Makefile
sem:comm.c sem.c 2 gcc -o $@ $^3 .PHONY:clean4 clean: 5 rm -f sem6
comm.h
1 #include <stdio.h>2 #include <sys/types.h>3 #include <sys/ipc.h>4 #include <sys/sem.h>5 6 7 #define PATHNAME "."8 #define PROJ_ID 0x66669 10 union semun{11 int val;12 struct semid_ds *buf;13 unsigned short *arr;14 struct seminfo *_buf;15 };16 int cerateSemSet(int nums);17 int initSem (int semid,int nums,int initVal);18 int P(int semid,int who);19 int V(int semid,int who);20 int destroySemSet(int semid);21 22 23
~
comm.c
1 #include "comm.h"2 3 static int commSemSet(int nums,int flags)4 {5 key_t _key=ftok(PATHNAME,PROJ_ID);6 if(_key<0){7 perror("ftork");8 return -1;9 }10 int semid=semget(_key,nums,flags);11 if(semid<0){12 perror("semget");13 return -2;14 }15 return semid;16 }17 int createSemSet(int nums){18 return commSemSet(nums,IPC_CREAT|IPC_EXCL|0666);19 }20 int getSemSet(int nums){21 return commSemSet(nums,IPC_CREAT);22 }23 24 int initSem(int semid,int nums,int initVal){25 union semun _un;26 _un.val=initVal;27 if(semctl(semid,nums,SETVAL,_un)<0){28 perror("semctl");29 return -1;30 }31 return 0;32 }33 34 static int commPV(int semid,int who,int op){35 struct sembuf _sf;36 _sf.sem_num=who;37 _sf.sem_op=op;38 _sf.sem_flg=0;39 if(semop(semid,&_sf,1)<0){40 perror("semop");41 return -1;42 }43 return 0;44 }45 46 int P(int semid,int who){47 return commPV(semid,who,1);48 }49 int V(int semid,int who){50 return commPV(semid,who,1);51 }52 53 int destroySemSet(int semid){54 if(semctl(semid,0,IPC_RMID)<0){55 perror("semctl");56 return -1;57 }58 }
sem.c
1 #include "comm.h"2 3 int main()4 {5 int semid=createSemSet(1);6 initSem(semid,0,1);7 pid_t id=fork();8 if(id==0){9 int _semid=getSemSet(0);10 while(1){11 P(_semid,0);12 printf("A");13 fflush(stdout);14 usleep(100000);15 printf("A");16 fflush(stdout);17 usleep(100000);18 V(_semid,0);19 }20 }21 else {22 while(1){23 P(semid,0);24 printf("B");25 fflush(stdout);26 usleep(100000);27 printf("B");28 fflush(stdout);29 usleep(100000);30 V(semid,0);31 }32 wait(NULL);33 }34 destroySemSet(semid);35 return 0;36 }
运行结果如下:
当我们再一次进行运行这个程序时,我们又会发现什么呢?
我们的解决的办法就是:
这篇关于【进程间通信】------信号量(sems)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!