死锁实例及避免策略

本文深入探讨了多线程编程中的死锁问题,包括死锁的定义、形成原因及条件,并通过具体实例展示了死锁发生的场景。最后,提出了有效的避免策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在多线程编程中,除了要解决数据访问的同步与互斥之外,还需要解决的重要问题就是多线程的死锁问题。所谓死锁: 是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外部处理作用,它们都将无限等待下去。

一、死锁原因与形成条件

  死锁形成的原因:

  1. 系统资源不足
  2. 进程(线程)推进的顺序不恰当;
  3. 资源分配不当

  死锁形成的条件:

  1. 互斥条件:所谓互斥就是进程在某一时间内独占资源。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
二、死锁实例
	//1.没有释放锁
	void  A()
	{
		mutex.lock();
		//这里操作共享数据
		if (.....)
		{

			return;
		}
		mutex.unlock();
		return;
	}
	//由于在if的执行体内直接retun,而没有调用unlock,导致另一个线程再调用A方法就出现死锁。又或者线程直接忘记释放锁也会引起死锁


	//2.单线程重复申请锁
	void  A()
	{
		mutex.lock();
		//这里操作共享数据
		mutex.unlock();
		return;
	}
	void  B()

	{
		mutex.lock();
		//这里操作共享数据
		A();  //这里调用A方法
		mutex.unlock();
		return;

	}


	//3.双线程多锁申请顺序不当

	void thread1()
	{
		lock(mutex1);
			...
		lock(mutex2);
			...
		unlock(mutex2);
		unlock(mutex1);
	}

	void thread2()
	{
		lock(mutex2);
		...
		lock(mutex1);
		...
		unlock(mutex1);
		unlock(mutex2);
	}

	//申请所没有按照顺序引起死锁


	//4.循环锁申请
	/* 多个线程申请锁的顺序形成相互依赖的环形:
	*             A   -  B
	*             |      |
	*             C   -  D
	*/

     假设有A、B、C、D四个人在一起吃饭,每个人左右各有一只筷子。所以,这其中要是有一个人想吃饭,
    他必须首先拿起左边的筷子,再拿起右边的筷子。现在,我们让所有的人同时开始吃饭。
    那么就很有可能出现这种情况。每个人都拿起了左边的筷子,或者每个人都拿起了右边的筷子,
    为了吃饭,他们现在都在等另外一只筷子。此时每个人都想吃饭,同时每个人都不想放弃自己已经得到的一那只筷子。
    所以,事实上大家都吃不了饭。

三、死锁避免

     死锁的代价是非常大的,有时候很难检测排查,因此需要在编程过程中尽可能的避免发生死锁。编程中为了避免死锁应该遵循如下策略:

(1)在编写多线程程序之前,首先编写正确的程序,然后再移植到多线程。
(2)时刻检查自己写的程序有没有在跳出时忘记释放锁。
(3)如果自己的模块可能重复使用一个锁,建议使用嵌套锁。
(4)对于某些锁代码,不要临时重新编写,建议使用库里面的锁,或者自己曾经编写的锁。
(5)如果某项业务需要获取多个锁,必须保证锁的按某种顺序获取,否则必定死锁。
(6)编写简单的测试用例,验证有没有死锁。
(7)编写验证死锁的程序,从源头避免死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值