线程死锁一引起的系列思考

发生死锁必须具备以下的4个条件

 

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

:资源是互斥的

2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

:如果只请求一个资源 那么也不会发现

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

:所有权

4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

:比如操作系统课老师举得例子 几个人吃饭,拿筷子问题 ,最后都会没拿到2只筷子而都吃不了饭

 

死锁例子

 static  std::recursive_mutex _mutex1;
static  std::recursive_mutex _mutex2;
int hp;

 int main(int argc, char *argv[])
{
  thread t ( []()
  {  
    _mutex1.lock();
    Sleep(12);
    _mutex2.lock();
   cout << "t:"<< hp << endl;
 
    _mutex1.unlock();
   _mutex2.unlock();
  });
  t.detach();
 
  _mutex2.lock();
  Sleep(12);
  _mutex1.lock();
  cout << "main:" << hp << endl;
 

  _mutex1.unlock();
  _mutex2.unlock();
 system("pause");
 return 0;
}

mutex1 mutex2 为2个资源,造成了环路等待条件 导致线程死锁

 

递归问题:递归加锁了 如

void doWith()
{
 _mutex1.lock();
 cout << "doWith:" << hp << endl;
  _mutex1.unlock();

} 
  int main(int argc, char *argv[])
 {
 
  thread t ( [=]()
  {  
    _mutex1.lock();
 
   cout << "t:"<< hp << endl;
   doWith();
     _mutex1.unlock();
 
  });
  t.detach();
  system("pause");
 return 0;
}

mutex被递归加锁了   而 std::mutex 非递归锁,子程序和 匿名函数  位于同一个线程空间     就又会造成 死锁,因为子程序在等待 匿名函数的解锁,而进入死锁

这时候可用 std::recursive_mutex  递归锁 替代std::mutex  或者自己实现一个递归锁

原理大致是 如果 和上次成功lock的操作的线程 不在同一线程 就真正的 lock 否则仅仅是引用计数加1

 以下是我的一个实现

class Re_mutex
{
public:
 void lock()
 {
  cout << "lock id "<<this_thread::get_id() << endl;
  if (this_thread::get_id() == _last_lock_id &&_islock == true)
  {
   ++count;
  }
  else
  {
   _last_lock_id = this_thread::get_id();
   _islock = true;
   _mutex.lock();
  }
 }

 void unlock()
 {
  --count;
  if (count == 0 && _islock)
  {
   _mutex.unlock();
  }
 }
private:
 bool _islock = false;
 mutex _mutex;
 int count = 0;
 thread::id _last_lock_id;
};
static  Re_mutex _mutex1;
//static  std::recursive_mutex _mutex2;
int hp;
void doWith()
{
 _mutex1.lock();
 cout << "doWith:" << hp << endl;
 _mutex1.unlock();

}

 int main(int argc, char *argv[])
 {
 
  thread t ( [=]()
  {  
    _mutex1.lock();
 
   cout << "t:"<< hp << endl;
   doWith();
    _mutex1.unlock();
 
  });
  t.detach();
 
 
 system("pause");
 return 0;
}

解决死锁的代价比较大,所以一般解决办法是 通过良好的设计 避免 死锁

你可能感兴趣的:(线程死锁一引起的系列思考)