哲学家就餐问题中的死锁
描述:在一张圆桌上,有n个哲学家,n支筷子,他们的生活方式只是交替地进行思考和进餐,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,进餐完毕,放下筷子又继续思考
若n位哲学家都各自获取了一只筷子,此时所有哲学家都想获取第二只筷子去吃饭,但是共享资源n只筷子已经都被n位哲学家握在手里了,彼此想要的筷子都在其他哲学家手中,又没有机制能让任何哲学家放弃握在手中的筷子,从而照成了所有哲学家都在等待其他人手中资源的死锁问题
计算机中死锁的产生
计算机中的资源通常分为两类:一类叫可重用资源,一类叫可消耗资源
可重用资源
一次只能供给一个进程安全的使用,并不会因为使用而耗尽。当一个进程使用完后,该资源就被归还。然后可以再供给其他进程或线程使用。例如内存,外设,处理器等资源
可消耗资源
指可以被创建和销毁的资源。例如在生产者消费者模型中,生产者生产产品创建了资源,消费者取走产品从而销毁了资源。常见的有:信号,消息等资源
竞争可重用资源产生死锁
例如现在内存大小共有4G。进程1总共需要3G,进程2总共需要3.5G。进程1首先申请了2G内存,进程2首先申请了1.5G内存,此时内存总量还剩余0.5G
当进程1想要在申请剩余的1G时,内存资源不够了。进程2想要在申请2G时,内存当然也不够了。此时,进程1希望进程2释放它所拥有的1.5G内存。进程2希望进程1释放它所拥有的2G内存。双方都占着自己所拥有的资源等待着对方释放资源,此时二者便陷入了死锁状态
竞争可消耗资源产生死锁
进程1和进程2之间通过消息进行通信。
1 进程1发送消息m1给进程2
2 进程2发送消息m2给进程1
3 进程1接收消息m2
4 进程2接收消息m1
如果按上述的1234顺序执行,二者之间便可以进行正常通信。但是如果执行顺序为:3412,此时二者都会发生阻塞而造成死锁
当一组进程中中的各进程都在等待某个事件发生(通常是等待资源的释放)但能够触发该事件的进程正处于阻塞中。此时,这组进程就发生了死锁
死锁产生的四个必要条件
当以下四个条件均满足时,才会产生死锁。只要有一个不满足。就不会产生:
互斥条件:各进程对某一资源必须是互斥的访问,当一个进程在访问时,请他进程只能等待
请求和保持条件:指进程已经拥有了一个资源,还要在申请另一个资源
不可抢占条件:资源在只能被申请它的进程使用完后自动释放,请他进程不能抢占
循环等待条件:如进程1等待进程2所拥有的资源,进程2等待进程3所拥有的资源,进程3等待进程1所拥有的资源
避免死锁
破坏死锁的四个必要条件、加锁顺序一致、避免锁未释放的场景、资源一次性分配
银行家算法
设requesti是进程Pi的请求量,如果requesti[j]=k,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,系统按下述步骤进行检查
- 如果requesti[j]>need[I,j]则出错,因为进程所需要的资源数已经超过它需要的最大值
- 如果requesi[j]>available[j]表示尚无足够的资源,Pi须等待
- 系统试探着把资源分配给进程Pi,并修改available、allocation、need的数值
- 系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,已完成本次资源的分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待
检测当前状态是否安全:
设置变量work:表示系统可提供给进程继续运行的剩余资源数。初始时,work=Available
设置变量finash:表示系统是否有足够的资源分配给某进程。如果有finash为true,如果没有为false,初始时,假设finash[i]为false
- 如果从进程集合中找到一个进程满足:finash[i]=false且Need[i,j]<work[j],则继续往下执行,若无则,跳转3
- 当进程i获取资源后,顺利执行,并释放资源:work[j]=work[j]+Allocation[i,j];finash[i] = true;继续回到1执行
- 当该进程组中所有进程的finash均变为true后,说明该系统处于安全状态。否则,为不安全状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| class Banker { public: Banker(const std::vector<int>& available , const std::vector<std::vector<int>>& max , const std::vector<std::vector<int>>& allocation) : _processNum(max.size()) , _resouceNum(max[0].size()) , _available(available) , _max(max) , _allocation(allocation) , _need(_processNum, std::vector<int>(_resouceNum, 0)) { for (int i = 0; i < _processNum; ++i) { for (int j = 0; j < _resouceNum; ++j) { _need[i][j] = _max[i][j] - _allocation[i][j]; } } }
void PrintSecurity() { std::cout << "安全序列为:" << std::endl; for (auto& i : _security) { std::cout << i << std::endl; } }
bool CheckRequest(int id, const std::vector<int>& request) { for (int i = 0; i < _resouceNum; ++i) { if (request[i] > _need[id][i]) { std::cerr << "请求资源数超过进程需求最大值" << std::endl; return false; }
if (request[i] > _available[i]) { std::cerr << "尚无足够资源,进程等待" << std::endl; return false; } }
for (int i = 0; i < _resouceNum; ++i) { _available[i] -= request[i]; _allocation[id][i] += request[i]; _need[id][i] -= request[i]; }
if (_checkSafe()) { std::cerr << "进程:" << id << "分配资源成功" << std::endl; return true; } else { std::cerr << "本次资源分配后系统不安全,分配失败" << std::endl; for (int i = 0; i < _resouceNum; i++) { _available[i] += request[i]; _allocation[id][i] -= request[i]; _need[id][i] += request[i]; } return false; } } private: bool _checkSafe() { std::vector<int> work(_available); std::vector<bool> finish(_processNum, false);
while (1) { int i; for (i = 0; i < _processNum; ++i) { if (finish[i] == true) { continue; } bool flag = true; for (int j = 0; j < _resouceNum; j++) { if (_need[i][j] > work[j]) { flag = false; break; } } if (flag == true) { _security.push_back(i); for (int j = 0; j < _resouceNum; j++) { work[j] += _allocation[i][j]; finish[i] = true; } break; } } if (i == _processNum) { for (int j = 0; j < _processNum; ++j) { if (finish[j] == false) { std::cerr << "系统处于不安全状态" << std::endl; return false; } } return true; } } } std::vector<int> _security; int _processNum; int _resouceNum; std::vector<int> _available; std::vector<std::vector<int>> _max; std::vector<std::vector<int>> _allocation; std::vector<std::vector<int>> _need; };
|