python线程池结束单个进程_Python 进程线程:Rlock

3d33ab28c137be325c0d5a36826c356c.png
10305

使用Rlock 进行线程同步

1.死锁

使用Lock 进行线程同步的时候,可能会造成死锁.

所谓死锁: 是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁.

多个线程获取多个锁,造成死锁

3af383eed5b07bb9a67e0cb5c46680a8.png
10023
"""
死锁
"""
import threading,time

class MyThread(threading.Thread):
 def __init__(self, lock1, lock2):
     self.alock = lock1
     self.block = lock2
     super(MyThread, self).__init__()

 def run(self):
     """acquire会返回布尔值"""
     if self.alock.acquire():
         print(self.name + ' up')
         time.sleep(1)
         if self.block.acquire():
             # self.block进入阻塞状态,等待self.alock释放锁
             print(self.name + ' down')
             self.block.release()
         self.alock.release()

class MyThread1(threading.Thread):
 def __init__(self, lock1, lock2):
     self.alock = lock1
     self.block = lock2
     super(MyThread1, self).__init__()

 def run(self):
     """acquire会返回布尔值"""
     if self.block.acquire():
         print(self.name + 'up')
         time.sleep(1)
         if self.alock.acquire():
             # self.alock进入阻塞状态,等待self.block释放锁
             print(self.name + 'down')
             self.alock.release()
         self.block.release()
         
if __name__ == '__main__':
 lock1 = threading.Lock()
 lock2 = threading.Lock()
 t1=MyThread(lock1, lock2)
 t2=MyThread1(lock1, lock2)
 t1.start()
 t2.start()

更简单的情况是,一个线程多次去获取锁,造成死锁

import threading
import time

num = 0

# 创建锁定池
mutex = threading.Lock()


class MyThread(threading.Thread):

def __init__(self):
  super(MyThread, self).__init__()

def run(self):
  global num
  time.sleep(1)
  # 获取锁
  if mutex.acquire(1):  # 设置了超时时间
      num += 1
      msg = "{} set num to {}".format(self.name, num)
      print(msg)
      mutex.acquire()   # 单一线程重复获取锁,锁没有释放,变成死锁
      mutex.release()
      mutex.release()


def main():
for i in range(5):
  t = MyThread()
  t.start()


if __name__ == '__main__':
main()

为了支持同一线程中,多次请求同一资源,python提供了Rlock 可重入锁.

2.可重入锁/递归锁

Rlock()Reentrant Lock:重入锁\递归锁说的都是它.这种锁对比Lock 有以下特点:

  • 谁拿到谁释放.如果线程A拿到锁,线程B无法释放这个锁,只有A可以
  • 同一线程可以多次拿到该锁,即可以多次acquire() .
  • acquire() 多少次就必须release() 多少次,只有最后一次释放锁才会改变锁的状态为Unlocked.

总结:

RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire.直到一个线程所有的acquire都被release,其他的线程才能获得资源.即对于同一线程而言,是可重入锁,而对于其他线程而言,和上面的Lock没有区别.

上面的例子使用Rlock 来替代,就不会发生死锁

import threading
import time

num = 0

# 创建锁定池,RLock 可以重复的上锁
mutex = threading.RLock()

class MyThread(threading.Thread):
 def __init__(self):
     super(MyThread, self).__init__()

 def run(self):
     global num
     time.sleep(1)
     # 获取锁
     if mutex.acquire(1):  # 设置了超时时间
         num += 1
         msg = "{} set num to {}".format(self.name, num)
         print(msg)
         mutex.acquire()   # 单一线程重复获取锁,锁没有释放,变成死锁
         mutex.release()
         mutex.release()

def main():
 for i in range(5):
     t = MyThread()
     t.start()

if __name__ == '__main__':
 main()

执行结果:

Thread-1 set num to 1
Thread-4 set num to 2
Thread-2 set num to 3
Thread-3 set num to 4
Thread-5 set num to 5

3.实例

构造一个Box 类,有add()remove()方法,提供了进入execute() 方法的入口,execute() 的执行由RLock() 来控制.这样每个函数的内部都实现了加锁和释放锁的操作,虽然获取多次锁,但是只有当一个线程完全释放了锁之后,另外一个线程才会去获取锁.

import threading,time

class Box:
 def __init__(self, obj_lock):
     self.total_items = 0
     self.lock = obj_lock

 def execute(self, n):
     self.lock.acquire()
     self.total_items += n
     self.lock.release()

 def add(self):
     self.lock.acquire()
     self.execute(1)
     self.lock.release()

 def remove(self):
     self.lock.acquire()
     self.execute(-1)
     self.lock.release()

# 两个方法
def adder(box, items):
 while items>0:
     print('adding 1 item in the box')
     box.add()
     time.sleep(1)
     items -= 1

def remover(box, items):
 while items>0:
     print('remove 1 item in the box')
     box.remove()
     time.sleep(1)
     items -= 1

if __name__ == '__main__':
 items = 5
 print('putting {} items in the box'.format(items))
 lock = threading.RLock()
 box = Box(lock)
 t1 = threading.Thread(target=adder, args=(box, items))
 t2 = threading.Thread(target=remover, args=(box, items))
 t1.start()
 t2.start()
 t1.join()
 t2.join()
 print('{} itesms still remain in the box'.format(box.total_items))

执行结果:

putting 5 items in the box
adding 1 item in the box
remove 1 item in the box
remove 1 item in the box
adding 1 item in the box
remove 1 item in the box
adding 1 item in the box
remove 1 item in the box
adding 1 item in the box
remove 1 item in the box
adding 1 item in the box
0 itesms still remain in the box
- END -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值