1://假设两个进程(父子进程)对一个文件进行写操作,但是这个文件同一时间只能有一个进程进行写操作。
2://利用信号量实现pv操作
3:#include
4:#include
5:#include
6:#include
7:#include
8:#include
9:struct sembuf sops;
10:static int sid;
11://创建一个新的信号量集
12:int createSemset(void)
13:{
14:char* pathname="semset";
15:if( access(pathname, F_OK)!=0 )
16:{
17:int fd=open(pathname, O_RDWR | O_CREAT, 0666);
18:if( fd<0 )
19:{
20:perror("open");
21:return -1;
22:}
23:}
24:key_t key=ftok(pathname, 'a');
25:if( -1==key )
26:{
27:perror("ftok");
28:return -1;
29:}
30:return semget(key, 1, IPC_CREAT | 0666) ;
31:}
32:
33://P操作
34:int P(void)
35:{
36:sops.sem_num=0;
37:sops.sem_op=-1;
38:sops.sem_flg=0;
39:return semop(sid, &sops, 1);
40:}
41://V操作
42:int V(void)
43:{
44:sops.sem_num=0;
45:sops.sem_op=1;
46:sops.sem_flg=0;
47:return semop(sid, &sops, 1);
48:}
49:int main(int argc, char *argv[])
50:{
51:sid=createSemset();
52:if( -1==sid )
53:{
54:perror("createSemset");
55:exit(1);
56:}
57:
58:if( -1==semctl(sid, 0, SETVAL, 1) )
59:{
60:perror("SETVAL");
61:exit(1);
62:}
63:pid_t pid=fork();
64:if( pid<0 )
65:{
66:perror("fork");
67:exit(1);
68:}
69:else if( 0==pid )
70:{
71:while(1)
72:{
73:if( -1==P() )
74:{
75:printf("P操作失败!
");
76:exit(1);
77:}
78:printf("子进程正在对文件进行写操作!
");
79:sleep(1);
80:printf("子进程写操作完毕,释放资源!
");
81:if( -1==V() )
82:{
83:printf("V操作失败!");
84:exit(1);
85:}
86:}
87:}
88:else
89:{
90:while(1)
91:{
92:if( -1==P() )
93:{
94:printf("P操作失败!
");
95:exit(1);
96:}
97:printf("父进程进程正在对文件进行写操作!
");
98:sleep(1);
99:printf("父进程写操作完毕,释放资源!
");
100:if( -1==V() )
101:{
102:printf("V操作失败!");
103:exit(1);
104:} ......
1:void P(int semid)
2:{
3: struct sembuf sem_p;
4: sem_p.sem_num = 0;
5: sem_p.sem_op = -1;
6: sem_p.sem_flg = SEM_UNDO;
7: if (semop(semid, &sem_p, 1) == -1) {
8: perror("p op failed
");
9: exit(1);
10: }
11:}
12:
13:void V(int semid)
14:{
15: struct sembuf sem_p;
16: sem_p.sem_num = 0;
17: sem_p.sem_op = 1;
18: sem_p.sem_flg = SEM_UNDO;
19: if (semop(semid, &sem_p, 1) == -1) {
20: perror("v op failed
");
21: exit(1);
22: }
23:}
PV原语通过操作信号量来处理进程间的同步与互斥的问题。其核心就是一段不可分割不可中断的程序。
信号量的概念1965年由著名的荷兰计算机科学家Dijkstra提出,其基本思路是用一种新的变量类型(semaphore)来记录当前可用资源的数量。有两种实现方式:1)semaphore的取值必须大于或等于0。0表示当前已没有空闲资源,而正数表示当前空闲资源的数量;2) semaphore的取值可正可负,负数的绝对值表示正在等待进入临界区的进程个数。
信号量是由操作系统来维护的,用户进程只能通过初始化和两个标准原语(P、V原语)来访问。初始化可指定一个非负整数,即空闲资源总数。
P原语:P是荷兰语Proberen(测试)的首字母。为阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;
V原语:V是荷兰语Verhogen(增加)的首字母。为唤醒原语,负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。
具体PV原语对信号量的操作可以分为三种情况:
1)把信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。
实现过程:
P(mutex); // mutex的初始值为1 访问该共享数据;
V(mutex);
非临界区
2)把信号量视为是某种类型的共享资源的剩余个数,实现对一类共享资源的访问。
实现过程:
P(resource); // resource的初始值为该资源的个数N 使用该资源;
V(resource); 非临界区
3)把信号量作为进程间的同步工具
实现过程:
临界区C1;
P(S);
V(S);
临界区C2;