【4858.com】可重入锁和互斥锁,自个儿成立锁及锁的档次

By admin in 4858.com on 2019年4月13日

python多进度,八线程之锁机制

python thread模块 锁 同步锁

Python中的线程是操作系统的原生线程,Python虚拟机使用3个大局解释器锁(Global
Interpreter
Lock)来互斥线程对Python虚拟机的应用。为了辅助多线程机制,2个中央的须求便是索要贯彻分化线程对共享财富访问的排外,所以引进了GIL。
GIL:在二个线程拥有理解释器的访问权之后,其余的全体线程都必须等待它释放解释器的访问权,就算那个线程的下一条指令并不会相互影响。
在调用任何Python C API以前,要先取得GIL
GIL缺点:多处理器退化为单处理器;优点:制止大批量的加锁解锁操作.

比喻讲解Python中的死锁、可重入锁和互斥锁,python互斥

一、死锁

粗略来说,死锁是四个能源被一再调用,而屡屡调用方都未能释放该能源就会造成死锁,那里结合例子表明下二种普遍的死锁意况。

1、迭代死锁

【4858.com】可重入锁和互斥锁,自个儿成立锁及锁的档次。该情况是1个线程“迭代”请求同三个资源,直接就会造成死锁:

import threading
import time
class MyThread(threading.Thread):
  def run(self):
    global num
    time.sleep(1)
    if mutex.acquire(1):
      num = num+1
      msg = self.name+' set num to '+str(num)
      print msg
      mutex.acquire()
      mutex.release()
      mutex.release()
num = 0
mutex = threading.Lock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

上例中,在run函数的if判断中第一回呼吁能源,请求后还未 release
,再次acquire,最后无力回天自由,造成死锁。那里例子中通过将print下边包车型大巴两行注释掉就足以健康实施了
,除却也能够通过可重入锁化解,后边会波及。

二、相互调用死锁

上例中的死锁是在同3个def函数内多次调用造成的,另1种情况是七个函数中都会调用相同的能源,相互等待对方截至的景况。假诺四个线程分别占据一部分财富并且还要等待对方的能源,就会招致死锁。

import threading
import time
class MyThread(threading.Thread):
  def do1(self):
    global resA, resB
    if mutexA.acquire():
       msg = self.name+' got resA'
       print msg
       if mutexB.acquire(1):
         msg = self.name+' got resB'
         print msg
         mutexB.release()
       mutexA.release()
  def do2(self):
    global resA, resB
    if mutexB.acquire():
       msg = self.name+' got resB'
       print msg
       if mutexA.acquire(1):
         msg = self.name+' got resA'
         print msg
         mutexA.release()
       mutexB.release()
  def run(self):
    self.do1()
    self.do2()
resA = 0
resB = 0
mutexA = threading.Lock()
mutexB = threading.Lock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

其1死锁的以身作则稍微有点复杂。具体能够理下。

2、可重入锁

为了帮助在同1线程中反复呼吁同一财富,python提供了“可重入锁”:threading.奥德赛Lock。奥迪Q⑤Lock内部维护着叁个Lock和一个counter变量,counter记录了acquire的次数,从而使得财富能够被反复require。直到3个线程全数的acquire都被release,别的的线程才能获得财富。那里以例一为例,假诺应用RubiconLock代替Lock,则不会时有产生死锁:

import threading
import time
class MyThread(threading.Thread):
  def run(self):
    global num
    time.sleep(1)
    if mutex.acquire(1):
      num = num+1
      msg = self.name+' set num to '+str(num)
      print msg
      mutex.acquire()
      mutex.release()
      mutex.release()
num = 0
mutex = threading.RLock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

和方面十三分例子的不一样之处在于threading.Lock()换来了threading.昂科拉Lock() 。

三、互斥锁 python threading模块有两类锁:互斥锁(threading.Lock
)和可重用锁(threading.陆风X8Lock)。两者的用法基本相同,具体如下:

lock = threading.Lock()
lock.acquire()
dosomething……
lock.release()

哈弗Lock的用法是将threading.Lock()修改为threading.CRUISERLock()。便于驾驭,先来段代码:

[[email protected] lock]# cat lock1.py

#!/usr/bin/env python
# coding=utf-8
import threading              # 导入threading模块
import time               # 导入time模块
class mythread(threading.Thread):    # 通过继承创建类
  def __init__(self,threadname):   # 初始化方法
    # 调用父类的初始化方法
    threading.Thread.__init__(self,name = threadname)
  def run(self):             # 重载run方法
    global x         # 使用global表明x为全局变量
    for i in range(3):
      x = x + 1
    time.sleep(5)     # 调用sleep函数,让线程休眠5秒
    print x
tl = []               # 定义列表
for i in range(10):
  t = mythread(str(i))        # 类实例化
  tl.append(t)           # 将类对象添加到列表中
x=0                 # 将x赋值为0
for i in tl:
  i.start() 

那边进行的结果和考虑的不如,结果如下:

[[email protected] lock]# python lock1.py

30
30
30
30
30
30
30
30
30
30

怎么结果都是30呢?关键在于global 行和 time.sleep行。

1、由于x是三个全局变量,所以每一遍循环后 x 的值都是执行后的结果值;

2、由于该代码是二10八线程的操作,所以在sleep
等待的时候,此前曾经施行到位的线程会在那等候,而再三再四的经过在等候的5秒那段日子也实施到位
,等待print。同样出于global 的法则,x被再次斌值。所以打印出的结果全是30

三、便于通晓,能够品味将sleep等注释,你再看下结果,就会意识有例外。

在其实应用中,如抓取程序等,也会并发就像于sleep等待的事态。在内向外调拨运输用有各种或打印有出口的时候,就会现并发竞争,造成结果或输出紊乱。那里就引进了锁的概念,上面包车型大巴代码修改下,如下:

[[email protected] lock]# cat lock2.py

#!/usr/bin/env python
# coding=utf-8
import threading              # 导入threading模块
import time               # 导入time模块
class mythread(threading.Thread):          # 通过继承创建类
  def __init__(self,threadname):         # 初始化方法
    threading.Thread.__init__(self,name = threadname)
  def run(self):             # 重载run方法
    global x            # 使用global表明x为全局变量
    lock.acquire()           # 调用lock的acquire方法
    for i in range(3):
      x = x + 1
    time.sleep(5)      # 调用sleep函数,让线程休眠5秒
    print x
    lock.release()        # 调用lock的release方法
lock = threading.Lock()        # 类实例化
tl = []             # 定义列表
for i in range(10):
  t = mythread(str(i))      # 类实例化
  tl.append(t)       # 将类对象添加到列表中
x=0            # 将x赋值为0
for i in tl:
  i.start()           # 依次运行线程

施行的结果如下:

[[email protected] lock]# python lock2.py

3
6
9
12
15
18
21
24
27
30

加锁的结果会导致堵塞,而且会导致开锁大。会基于种种由并发的八线程按梯次输出,借使后边的线程执行过快,要求拭目以俟眼下的经过截至后其才能了事
--- 写的相似有点像队列的定义了
,不过在加锁的居多情景下真的能够透过队列去解决。

一、死锁
不难的话,死锁是一个能源被频仍调用,而频仍调用方都不可能释放该财富…

在应用拾二线程的应用下,如何确认保障线程安全,以及线程之间的共同,恐怕访问共享变量等难题是格外困难的标题,也是应用十二线程下边临的标题,如若处理不佳,会带来较严重的结果,使用python拾贰线程中提供Lock
猎豹CS陆lock Semaphore 伊夫nt Condition
用来担保线程之间的一路,后者保障访问共享变量的排外难题

锁添加的来头:

2.叁.一 GIL的早期规划

Python协助多线程,而消除102线程之间数据完整性和意况同步的最简便方法自然正是加锁。
于是有了GIL那把顶尖大锁,而当越来越多的代码库开发者接受了那种设定后,他们起头大量依靠那种特点(即暗中认可python内部对象是thread-safe的,无需在贯彻时思考外加的内部存款和储蓄器锁和同步操作)。渐渐的那种完毕格局被发觉是蛋疼且低效的。但当大家试图去拆分和去除GIL的时候,发现多量库代码开发者现已重度依赖GIL而特出不便去除了。有多难?做个类比,像MySQL那样的“小品种”为了把Buffer
Pool
Mutex那把大锁拆分成各类小锁也花了从5.伍到伍.陆再到伍.柒多少个大版为期近5年的时刻,并且仍在继续。MySQL这几个背后有店铺帮衬且有定位开支协会的制品走的这么困难,那又加以Python这样主旨开发和代码贡献者中度社区化的团队吗?

Lock & 汉兰达Lock:互斥锁 用来保险四线程访问共享变量的难题
Semaphore对象:Lock互斥锁的压实版,能够被多少个线程同时具有,而Lock只能被某二个线程同时负有。
伊夫nt对象:
它是线程间通讯的法子,也就是功率信号,1个线程能够给别的一个线程发送非非确定性信号后让其推行操作。
Condition对象:其能够在壹些事件触发或然达到一定的尺度后才处理数量

在多进程/二拾十二线程同时进入临界财富区获取和操作共有财富时,晤面世财富的互殴而出现混乱。为了防止这种紊乱境况,python建议了锁机制

2.3.2 GIL的影响

不管你启多少个线程,你有个别许个cpu,
Python在进行一个历程的时候会淡定的在同样时刻只允许三个线程运转。
故此,python是心有余而力不足选用多核CPU完毕102线程的。
如此那般,python对于计算密集型的天职开十贰线程的频率甚至比不上串行(未有大气切换),不过,对于IO密集型的任务成效依旧有拨云见日提高的。

4858.com 1

 

由此对于GIL,既然不能够抵挡,那就学会去分享它吧!

同步锁

锁常常被用来达成对共享财富的联合访问。为各种共享能源创立三个Lock对象,当您必要拜访该财富时,调用acquire方法来获得锁对象(即便其它线程已经得到了该锁,则当前线程需等候其被保释),待财富访问完后,再调用release方法释放锁。

 

4858.com 24858.com 3

 1 import threading
 2 
 3 import time
 4 def sub():
 5     global num   #引用全局变量
 6     lock.acquire()     #启动锁
 7     temp=num      #赋值变量
 8     time.sleep(0.1)   睡眠
 9     num=temp-1        #变量自减一
10     lock.release()      #关闭锁
11 
12     time.sleep(2)   #睡眠时间
13 num=100   #全局变量
14 l=[]     #定义空的字典
15 lock=threading.Lock()     #创建锁
16 for i in range(100):  # #创建线程的数量
17     t=threading.Thread(target=sub,args=())    #创建对象线程
18     t.start()     #启动对象线程
19     l.append(t)   #将对象线程写入空字典中
20 for t in l:
21     t.join()    #主线程运行完后,子线程才能运行
22 print(num)

View Code

 

import threading

 

R=threading.Lock()

 

R.acquire()
”’
对公共数据的操作
”’
R.release()

 

所谓死锁:
是指四个或八个以上的进度或线程在履行进程中,因争夺能源而招致的一种互动等待的场地,若无外力作用,它们都将不能推进下去。此时称系统处于死锁状态或系统发生了死锁,那个永恒在相互等待的进程称为死锁进程。

4858.com 44858.com 5

 1 import threading
 2 import time
 3 class MyThread(threading.Thread):   ##创建一个子类,父类是(threading.Thread)
 4     def __init__(self):
 5         threading.Thread.__init__(self)         #调用父类的功能
 6     def run(self):              #用父类的功能
 7         self.foo()             #调用自己的功能
 8         self.fo()                #调用自己的功能
 9     def foo(self):           #创建自己的功能
10         LockA.acquire()        #开启大锁
11         print('qqqqq')         #启动功能
12         LockB.acquire()       #开启小锁
13         print('wwwww')      #启动功能
14         LockB.release()       #关闭小锁
15         LockA.release()      #关闭大锁
16     def fo(self):          #创建自己的功能
17         LockB.acquire()   #开启小锁
18         print('lllll')      #启动功能
19         LockA.acquire()       #开启大锁
20         time.sleep(1)
21         print('dddddd')      #启动功能
22         LockA.release()       #关闭大锁
23         LockB.release()      #关闭小锁
24 LockA=threading.Lock()       #创建大锁
25 LockB=threading.Lock()       #创建小锁
26 for i in range(10):       #创建线程的数量
27     t=MyThread()      #创建对象
28     t.start()         #启动对象  #两个锁同时运行,但是两个锁会打结,一个等待着一个
29     t.run()       #对象调用父类下的功能,相当于串型

View Code

 

在Python中为了援助在同壹线程中1再请求同一财富,python提供了可重入锁LANDLock。那么些途胜Lock内部维护着二个Lock和二个counter变量,counter记录了acquire的次数,从而使得财富能够被一再require。直到三个线程全数的acquire都被release,其他的线程才能获取能源。上边的例证假若利用奥迪Q三Lock代替Lock,则不会发生死锁。

 

4858.com 64858.com 7

 1 import threading
 2 import time
 3 class MyThread(threading.Thread):    #调用父类的功能
 4     def __init__(self):
 5         threading.Thread.__init__(self)
 6     def run(self):
 7         self.foo()
 8         self.fo()
 9     def foo(self):
10         Lock.acquire()     #
11         print('qqqqq')
12         Lock.acquire()
13         print('wwwww')
14         Lock.release()
15         Lock.release()
16     def fo(self):
17         Lock.acquire()
18         print('qqqqq')
19         time.sleep(1)
20         Lock.acquire()
21         print('wwwww')
22         Lock.release()
23         Lock.release()
24 Lock=threading.RLock()   #创建一个锁R
25 for i in range(10):
26     t=MyThread()
27     t.start()

View Code

 

Semaphore管理一个放到的计数器,
每当调用acquire()时内置计数器-一;
调用release() 时内置计数器+1;
计数器无法小于0;当计数器为0时,acquire()将卡住线程直到其余线程调用release()。

实例:(同时只有几个线程能够得到semaphore,即能够限制最安卡拉接数为5):

 

4858.com 84858.com 9

 1 import threading
 2 import time
 3 
 4 semaphore=threading.Semaphore(5)   #创建同时执行的数量
 5 def foo():      #创建对象
 6     semaphore.acquire()    #启动执行的数量
 7     time.sleep(0.1)     #睡眠时间
 8     print('sb')     #打印
 9     semaphore.release()      #关闭执行数量
10 
11 for i in range(100):  #创建线程的数量
12     t=threading.Thread(target=foo,args=( ))     #创建对象线程
13     t.start()       #启动对象线程

View Code

 

Lock与Rlock的区别

那二种锁的基本点差异是:福特ExplorerLock允许在同1线程中被多次acquire。而Lock却不容许那种意况。注意:假若接纳EnclaveLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正自由所占据的琐。

  

1、Lock(互斥锁)

 

伸手锁定 — 进入锁定池等待 — 获取锁 — 已锁定 — 释放锁

线程锁/进度锁的定义和平运动用:

Lock(指令锁)是可用的最低级的一路指令。Lock处于锁定状态时,不被一定的线程拥有。Lock包涵二种状态——锁定和非锁定,以及八个着力的方法。

成立锁对象:

能够认为Lock有二个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

lock = Lock()

构造方法:
Lock()

锁对象壹旦创设,就能够每一天被进程大概线程调用,并且二遍创立锁只有1把,假使八个财富想同时获得锁,必须‘排队’,等上一个进度/线程释放了锁才足以请求获取锁

实例方法:
acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。
release(): 释放锁。使用前线程必须已收获锁定,不然将抛出尤其。

 

if mutex.acquire():
 counter += 1
 print "I am %s, set counter:%s" % (self.name, counter)
  mutex.release()

上锁(也叫请求锁)

2、翼虎Lock(可重入锁)

lock.acquire()

卡宴Lock(可重入锁)是三个足以被同贰个线程请求数次的1块指令。XC60Lock使用了“拥有的线程”和“递归等级”的定义,处于锁定状态时,奥迪Q五Lock被有些线程拥有。拥有奔驰M级Lock的线程能够另行调用acquire(),释放锁时需求调用release()相同次数。

acquire()是一个梗阻函数。一旦请求获取锁成功,就会把上边将要执行的顺序的变量内部存款和储蓄器空间‘锁住’;而获取不成功则会直接不通在那边,等待上贰个获得锁的历程/线程释放锁。

能够认为ENCORELock包涵3个锁定池和3个初始值为0的计数器,每回成功调用
acquire()/release(),计数器将+1/-壹,为0时锁处于未锁定状态。

 

构造方法:
RLock()

解锁

实例方法:
acquire([timeout])/release(): 跟Lock差不多。

lock.release()

3、Semaphore(共享对象访问)

 

大家再聊聊Semaphore
,说实话Semaphore是自小编最晚利用的1块儿锁,在此之前类似的贯彻,是本身用奥德赛lock完毕的,相对来说有些绕,毕竟LX570lock
是必要成对的锁定和开锁的》。。。

 

Semaphore管理3个放到的计数器,
每当调用acquire()时内置计数器-一;
调用release() 时内置计数器+壹;
计数器不可能小于0;当计数器为0时,acquire()将卡住线程直到别的线程调用release()。

死锁:

平昔上代码,大家把semaphore控制为三,也正是说,同时有一个线程能够用那个锁,剩下的线程也之只好是阻塞等待了…

死锁的出现有三种意况

#coding:utf-8
#blog xiaorui.cc
import time
import threading

semaphore = threading.Semaphore(3)

def func():
 if semaphore.acquire():
  for i in range(3):
   time.sleep(1)
   print (threading.currentThread().getName() + '获取锁')
  semaphore.release()
  print (threading.currentThread().getName() + ' 释放锁')


for i in range(5):
 t1 = threading.Thread(target=func)
 t1.start()

一)
当贰个历程或许五个线程一直调用或然占有同样锁Lock而不自由财富而招致别的进度/线程不可能获得锁,就会油然则生的死锁处境,一直不通在aquire()处

四、伊芙nt(线程间通讯)

二)
当有七个进度同时想博得七个锁的时候(再往上推正是八个经过想赢得多少个锁),由于两岸都以由于竞争关系,哪个人也不让何人,什么人快哪个人得手,但总结机中那种竞争关系是很神秘的,时间的差别性一点都不大,于是,就出现了2者都短路在同三个地点,都爱莫能助同时获取多个锁如故取得对方早已收获的但还尚未自由的锁。

伊芙nt内部含有了2个标志位,伊始的时候为false。
可以选择应用set()来将其设置为true;
抑或采纳clear()将其从新安装为false;
能够使用is_set()来检查标志位的动静;

 

另二个最关键的函数正是wait(timeout=None),用来阻塞当前线程,直到event的在这之中标志位被安装为true可能timeout超时。假诺内部标志位为true则wait()函数理解再次回到。

为了消除死锁的标题,于是python建议了可重入锁的编写制定(RAV4Lock)

import threading
import time

class MyThread(threading.Thread):
 def __init__(self, signal):
  threading.Thread.__init__(self)
  self.singal = signal

 def run(self):
  print "I am %s,I will sleep ..."%self.name
  self.singal.wait()
  print "I am %s, I awake..." %self.name

if __name__ == "__main__":
 singal = threading.Event()
 for t in range(0, 3):
  thread = MyThread(singal)
  thread.start()

 print "main thread sleep 3 seconds... "
 time.sleep(3)

 singal.set()

重入锁定义后,三个进度就能够重复调用钦命次数的贰个重入锁,而不用去跟别的进度1起角逐其他锁。

五、Condition(线程同步)

 

可以把Condition掌握为1把高档的琐,它提供了比Lock,
悍马H2Lock越来越尖端的法力,允许大家能够支配复杂的线程同步难题。threadiong.Condition在里边维护二个琐对象(暗许是讴歌RDXLock),可以在开立Condigtion对象的时候把琐对象作为参数字传送入。Condition也提供了acquire,
release方法,其意思与琐的acquire,
release方法同样,其实它只是简短的调用内部琐对象的呼应的主意而已。Condition还提供了如下方法(特别要专注:这几个主意唯有在挤占琐(acquire)之后才能调用,不然将会报RuntimeError极度。):

重入锁中内部管理者多少个对象,即Lock对象和锁的调用次数count

Condition.wait([timeout]):

4858.com ,上面说说酷路泽Lock到底是怎么用的

wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通报被提醒或逾期(假诺提供了timeout参数的话)。当线程被晋升并再次占有琐的时候,程序才会继续执行下去。

1)RLock的定义

Condition.notify():

mutexA = mutexB = RLock( )

唤醒二个挂起的线程(若是存在挂起的线程)。注意:notify()方法不会放出所占用的琐。

mutex值能够是五个的,定义了不怎么个,帕杰罗Lock内部的count就为几

Condition.notify_all()
Condition.notifyAll()

 

唤醒全部挂起的线程(即使存在挂起的线程)。注意:那几个办法不会自由所占据的琐。

2)RLock的请求

对此Condition有个例证,大家能够目睹下。

mutexA.acquire()

from threading import Thread, Condition
import time
import random

queue = []
MAX_NUM = 10
condition = Condition()

class ProducerThread(Thread):
 def run(self):
  nums = range(5)
  global queue
  while True:
   condition.acquire()
   if len(queue) == MAX_NUM:
    print "Queue full, producer is waiting"
    condition.wait()
    print "Space in queue, Consumer notified the producer"
   num = random.choice(nums)
   queue.append(num)
   print "Produced", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


class ConsumerThread(Thread):
 def run(self):
  global queue
  while True:
   condition.acquire()
   if not queue:
    print "Nothing in queue, consumer is waiting"
    condition.wait()
    print "Producer added something to queue and notified the consumer"
   num = queue.pop(0)
   print "Consumed", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


ProducerThread().start()
ConsumerThread().start()

mutexA.acquire()

如上正是本文的全部内容,希望对大家的求学抱有协助,也希望我们多多帮忙脚本之家。

 

您或然感兴趣的文章:

  • python10二线程threading.Lock锁用法实例
  • Python十2线程编程(四):使用Lock互斥锁
  • python线程锁(thread)学习示例
  • Python中八线程及顺序锁浅析
  • Python10贰线程编程(5):死锁的变异
  • Python多线程编制程序(6):可重入锁BMWX三Lock
  • 简不难单讲解Python编制程序中线程的创导与锁的应用
  • Python落成的八线程同步与排斥锁作用示例
  • 比喻讲解Python编制程序中对线程锁的行使
  • 详解python10贰线程、锁、event事件机制的简便利用
  • Python拾2线程中梗阻(join)与锁(Lock)使用误区解析
  • Python四线程编制程序之多线程加锁操作示例

每申请二回锁,count就减一,三遍呼吁过后,count从2减为0

 

因为下边定义的重入锁的内部个数为2,所以该重入锁能够被多少个进程调用两回,并且在纵然它里面有多少个锁,但不得不由一个进度/线程调用,别的进度/线程不能够干预,唯有当以此历程/线程释放掉全体的重入锁,count=贰时才能够被其余进度/线程调用。

 

三)RubiconLock锁的释放

mutexA.release()

mutexB.release()

 

举例:

from multiprocessing import RLock,Process
from time import ctime,sleep

muxteA = mutexB =RLock()

def fn1():
    muxteA.acquire()
    sleep(1)
    print(ctime(),'进程1获取A锁')
    mutexB.acquire()
    sleep(2)
    print(ctime(),'进程1获取B锁')
    muxteA.release()
    print('进程1释放A锁')
    mutexB.release()
    print('进程1释放B锁')

def fn2():
    muxteA.acquire()
    sleep(1)
    print(ctime(),'进程2获取A锁')
    mutexB.acquire()
    sleep(1)
    print(ctime(),'进程2获取B锁')
    muxteA.release()
    print('进程2释放A锁')
    mutexB.release()
    print('进程2释放B锁')


p1 = Process(target=fn1)
p2 = Process(target=fn2)
p1.start()
p2.start()

p1.join()
p2.join()

 结果如下:

4858.com 10

 

那就是说只要本身让进程2先开启呢?

4858.com 11

 

结果如下:

4858.com 12

 

家弦户诵,锁的得到是什么人快何人得手,同时也证实了自作者上边描述的,三个过程对四个可重入锁的请求是排他型的,一旦那一个历程请求了三个可重入锁,那么其余进度就无法再请求了,直到这些进度释放了可重入锁中间的有所锁。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有