一直想看看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:clean
4 clean:
5 rm -f sem
6
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 0x6666
9
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 }
运行结果如下:
当我们再一次进行运行这个程序时,我们又会发现什么呢?
我们的解决的办法就是: