进程互斥软件实现之Dekker算法
一. 为什么需要互斥?
大多数系统允许多个进程共享资源(如CPU,IO设备,硬盘等), 为了保证进程间能够互不影响、安全正确地访问这些共享资源, 就必须对进程访问共享资源采取互斥控制.
进程互斥原则: 有限等待, 空闲让进
二. 名词说明:
临界资源: 对于某一时刻仅允许一个进程访问的共享资源.
临界区: 访问临界资源的程序代码段.
互斥: 对进程排它地访问临界资源的控制手段, 某一时刻临界区的进程只能为一个.
三. Dekker算法思想:孔融让梨, 任意进程在访问关键区之前会先检查其它进程是否也需要使用关键区,如果其它进程也需要使用关键区,并且其它进程也拥有执行权限,这时当前进程就会等待其它进程访问关键区完毕,若其它进程无法同时满足两个条件,那么当前进程就会直接访问关键区域.
伪代码:
1 // 变量说明: 2 // flag[0] = true 表示进程P0需要使用关键区 3 // flag[1] = false 表示进程P1不需要使用关键区 4 // turn = 0 表示进程P0具有访问权限 5 // turn = 1 表示进程P1具有访问权限 6 7 /* 进程P0行为 */ 8 void P0() 9 { 10 while (true) 11 { 12 // P0需要使用关键区 13 flag[0] = true; 14 // 检查P1是否也需要 15 while (flag[1]) 16 { 17 // 检查P1是否具有访问权限 18 if (turn == 1) 19 { 20 // P1也需要,P0让给P1 21 flag[0] = false; 22 // P0等待P1执行完毕 23 while (turn == 1); 24 flag[0] = true; 25 } 26 } 27 28 // 临界区代码 29 30 // 访问完成,将权限归还P1 31 turn = 1; 32 // 进程P0使用完毕 33 flag[0] = false; 34 } 35 } 36 37 /* 进程P1行为, 与进程P0类似 */ 38 void P1() 39 { 40 while (true) 41 { 42 flag[1] = true; 43 while (flag[0] == 1) 44 { 45 if (turn == 0) 46 { 47 flag[1] = false; 48 while (turn == 0); 49 flag[1] = true; 50 } 51 } 52 53 // 临界区代码 54 55 turn = 0; 56 flag[1] = false; 57 } 58 } 59 60 main() 61 { 62 // 创建两个线程t1和t2 63 pthread_t t1, t2; 64 65 // 初始化条件 66 flag[0] = flag[1] = 0; 67 turn = 0; 68 69 int err; 70 71 // 线程t1模拟进程P0 72 err = pthread_create(&t1, NULL, (void*)P0, NULL); 73 if (err != 0) exit(-1); 74 // 线程t2模拟进程P1 75 err = pthread_create(&t2, NULL, (void*)P1, NULL); 76 if (err != 0) exit(-1); 77 78 pthread_join(t1, NUll); 79 pthread_join(t2, NUll); 80 81 exit(0); 82 }
不能再用单进程编程那样一段代码从头执行到底的"直线式"思维了。这是多进(线)程编程, 程序完全有可能在执行到任意一条语句时被中断, 从而跳到另外一个进程执行另外一段代码.
Dekker算法仅能进行两个进程的互斥,对于两个以上的互斥问题,实现起来相当复杂.
总之,Dekker算法首先使用状态值的方式解决了序号访问临界区的弊端,使得进程可以互斥的访问临界资源,而最后结合了序号谦让方式解决了因为避免死锁而产生的僵局现象,就这样循序渐进地用软件方法解决了进程的互斥的问题.
参考:
https://blog.csdn.net/wsw875421872/article/details/17222219