最近在刷面经的时候经常能看到诸如一个进程如何判断另外一个进程是否死锁的问题?然后各种百度,得到答案主要有两种,一种是通过查看线程栈帧是否一直wait在某个地方,另外一种是通过对所有的锁资源建立资源分配图,如下图:
图中箭头指向P代表P已经获取到该资源,而箭头指向R代表R真在被申请。在这张图中就是
P1:获取到两个R1,申请一个R2
P2:获取到一个R1,申请一个R2
当前并没出现死锁,因为R2的资源足够分配给P1,P1处理完退回R1,则P2能够获取到所有的资源并去处理。
但是假如R2只有一个,则P1无法申请到R2,从而无法退回R1,则会导致P2也申请不到R1,进而互相等待,即死锁。
在这个地方我们首先需要考虑的解决问题,是在某个检测线程中能够获取到所有资源的分配情况。但是这个问题我也是找了很久的api,始终没找到能获取到某个mutex被占有的情况。
所以我想了一个思路就是通过继承拓展已有的类资源,这样重写方法没那么多,这个方法在java里面应该没什么问题,但是在C++里面,因为mutex继承自_Mutex_base,而_Mutex_base的析构方法并不是虚的,这样就会导致一些问题,比如我们的继承类的析构函数可能会执行不到,从而导致内存泄漏。所以这里我们在用组合的方式进行。
这里有个简单的参考实现
class MyMutex {
public:
bool locked = false;
decltype(this_thread::get_id()) id;
mutex m;
void lock() {
m.lock();
cout << "thread :" << this_thread::get_id() <<" --> lock" << endl;
id = this_thread::get_id();
locked = true;
}
void unlock() {
if (id == this_thread::get_id()) {
cout << "thread :" << this_thread::get_id() << " --> unlock" << endl;
id = thread::id();
locked = false;
m.unlock();
}
}
auto lockThread()->decltype(auto) {
return id;
}
};
测试代码:
int main() {
MyMutex m;
vector<thread> p;
m.lock();
m.unlock();
unique_lock ul{m};
for (int i = 0; i < 4;i++) {
p.push_back(thread{ [&m] {
Sleep(500);
cout << "childe m:" << this_thread::get_id() << endl;
{
lock_guard<MyMutex> lg{ m };
}
} });
}
ul.unlock();
cout << "main:" << this_thread::get_id() << endl;
while (true) {
cout <<"main m:"<< m.lockThread() << endl;
Sleep(1000);
}
return 0;
}
输出结果:
通过这样我们就能简单的实现锁资源的占有情况进行分析,从而能够建立资源分配图来进行程序内的死锁分析,进而进行死锁解除操作。