死锁,并发,并行,抢购概念的很多疑惑

首先,死锁是怎样产生的 ?

网上的好多回答都是照搬的如下概念:

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。

  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

  3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。*

我的问题是:看了这里的介绍 , 发现貌似并发确实是会产生死锁的, 个人认为, 因为并发状态下, 可能CPU在处理某个进程的时候, 其他进程需要等待CPU切换过来找自己, 等待的过程我个人觉得就是阻塞着,也就是死锁着, 不知道理解对不对 !

另外, 看到很多人说抢购/秒杀系统, 在高并发下会带来多卖的风险, 这个我就更加不能理解了 :

按照我小菜的思维, 假设抢购1000个商品, 假设有100个请求在某一个CPU时间内一次性挤入了CPU内, 假设CPU是单核的, 那么并发不是CPU一个个不断地切换处理么? 既然这样, 也就是CPU会一个个地处理对商品的减操作, 这样的话, 每次操作的时候我判断商品剩余数量不就行了, 怎么可能多卖!!! 所以这里需要大牛稍微帮忙给解释一下

还有就是并行

假设有4个请求在某一个CPU时间内一次性挤入了CPU内, 而我们的CPU是4个核心的, 那么四个核心同时处理4个抢购进程进行商品数量递减的时候, 这个小菜认为: 这倒是确实会出现同时锁住这条商品记录导致任何一个核心都无法释放而产生死锁! 但问题是:

  1. 自己底层知识不够, 不知道是不是这4个请求一定就会分配个每个核心, 还是会全部分配到一个核心上, 再或者说压根就是随机分配 (比如核心一上2个请求,核心二上1个请求,核心三上1个请求,核心4上没有请求)? 但不管怎么说, 既然死锁了, 也不会出现抢购超卖了啊!

  2. 第二个问题是: 如果请求数量大于4个, 比如说又是100个一次性挤入了CPU内, 这时候, 又出现了并发, 而不是并行, 可能每个CPU都会进行轮训处理并发的请求 ;

阅读 7.5k
4 个回答
  1. PHP是高级语言,不用考虑CPU的问题,每个请求都会分配给一个进程,php自己会去管理进程调用什么资源的。你说的死锁,应该是数据库的吧,不是进程的。

  2. 100个进程挤进去一个CPU。。CPU也会正常去一个个处理完的。。。

好了。。来说说你问的问题吧。。我尝试梳理了好久猜测你问的是啥。。简单的说下吧。。

死锁是怎么产生的

笼统点说。mysql每次对某一堆数据修改或者查询(innodb在某些条件下不受这个限制)的时候。。。会告诉系统,这片数据我要用。。别人不能动。。。然后别人再来用的时候,系统就会告诉别人。。某某某在用着这片数据,你等等。。然后别人就等着了。。。这就叫锁。。
那死锁是怎么回事呢?有的数据是有关联的,例如秒杀,你要先扣库存,还要写订单。。所以就会高速系统,库存这个你先给我锁住,等我写完订单回来,改完库存,你再把两个都放开。。。
如果这时候有另外一个人执行着相反的事情。。要先锁住订单表。然后去改库存表。
那就可能死锁,来慢镜头模拟下。。。

A:系统!锁库存表,我要去写订单表。。 系统:好的!搞定。。 B:系统!锁订单表,我要去改库存表。。 系统:好的!搞定。。

A:系统,我要写订单~ 系统:抱歉,B用户占用着,你等等。 A: 哦~

B:系统,我要改库存表 系统:抱歉,A用户占用着,你等等。 B: 哦~

几个小时过去了... A:B搞什么鬼,还没用完。。 B:A搞什么鬼,还没用完。。

服务器:你们搞什么鬼,几百万用户等着呢。。

理解了么?附代码:

SELECT `product` WHERE `pid` = 1 FOR UPDATA;
UPDATA `order` SET `status` = 1 WHERE `uid` = 2 AND `pid` = 1;
SELECT `order` WHERE `uid` = 2 FOR UPDATA;
UPDATA `product` SET `num` = `num` + 1 WHERE `oid` = 3;

想真实体验,就让他两条中间sleep几秒,同时请求两边,就锁住了,直到超时

这个确实把死锁说的很清楚了,原来死锁是这么产生的,我问题中的死锁也确实是数据库的死锁
那对于死锁,我觉得是个碰巧出现的事情,觉着业务逻辑如果很复杂的话,还是很容易出现这种巧合的,比如innodb下一个业务逻辑1需要一个事务(会操作a,b两张表各自的某条记录)进行完成时候,完全有可能在操作进行到a表某条记录操作刚完成的时候,也就是正准备操作b表记录时; 突然间有另一条业务逻辑2请求被cpu切换到了(巧了,它也用事务并且先操作b表的同逻辑1的记录,再操作
a表同逻辑1的记录),而他正好操作完b表的该条记录,准备请求这样目前被锁住的情况就导致逻辑一不能进行,逻辑二也不能进行! 理解的对么?

那对于为什么并发会产生多卖我还没有清楚啊,如若按照你说的,cpu总会一个个的处理请求, 那处理每个请求的时候我都判断当前库存,根本不会出现超出库存的啊

还有,您说的并发是一个一个请求进行处理 这是单cpu会出现的或者请求数大于cpu个数会出现的

如果是cpu有5颗,只过来3个请求,每个请求都要操作a表的1记录,那还真有可能3颗cpu并行同时抓住a表的1记录,这样也是死锁么? 还是说,虽然cpu并行到达这条记录,但数据库只会允许一个个来加锁,即使同时到达,但mysql还是会排队,这并不算死锁?

秒杀超额的问题我的理解很简单,比如多线程并发情况下
A用户读取到商品还有100件
与此同时,按照你的理解,CPU切换需要时间
B用户在这时候刚好进来(A还没有来得及给商品-1),读取到商品也是100
这时候就会有问题了

问者好混乱的思维。
阻塞或者系统调度把cpu让出去,等待下次调度,并不会造成死锁。
死锁是两个以上计算单元(进程,线程,纤程)各自acquire了一个锁又去尝试acquire对方acquired的,才会一直阻塞造成死锁。mysql的话,上面的锁可能是表锁或者行锁。
死锁跟你硬件几个cpu核无关。

并发是你宏观上让几件事同时在做,微观来看如果cpu只有一个的话,这几件事分步骤交替使用cpu。如果这时候有多个cpu核心的话,就真正实现了计算的并行。所以就算你只有一个cpu, Linux系统下top一下也能看到好多个进程同时存在,你用其中一个tty用起来却不会卡。

推荐问题
宣传栏