1.1死锁发生的必要条件
1.2.1死锁例子 简单模拟银行转账
"""
银行转账
"""
from time import sleep
from threading import Thread,Lock
# 账户类
class Account:
def __init__(self, _id, balance, lock):
self.id = _id # 用户
self.balance = balance # 存款
self.lock = lock # 锁
# 取钱
def withdraw(self, amount):
self.balance -= -amount
# 存钱
def deposit(self, amount):
self.balance += amount
# 查看余额
def get_balance(self):
return self.balance
# 产生两个账户
Tom = Account('Tom', 5000, Lock())
Alex = Account('Alex', 8000, Lock())
# 转账过程
def transfer(from_, to, amount):
if from_.lock.acquire(): # 锁住自己的账户
from_.withdraw(amount)
sleep(0.5)
if to.lock.acquire(): # 锁住自己的账户
to.deposit(amount) # to账户加钱
to.lock.release() # to账户解锁
from_.lock.release() # from账户解锁
print("%s给%s转账%d"%(from_.id, to.id, amount))
t1 = Thread(target = transfer, args = (Tom, Alex, 2000))
t2 = Thread(target = transfer, args = (Alex, Tom, 1000))
t1.start()
t2.start()
运行结果:执行两个线程就会形成死锁
解锁位置不对
from_, to 独立进行 解锁并上锁则不会出现死锁现象
1.2.2正确代码
"""
死锁例子
银行转账
"""
from time import sleep
from threading import Thread,Lock
# 账户类
class Account:
def __init__(self, _id, balance, lock):
self.id = _id # 用户
self.balance = balance # 存款
self.lock = lock # 锁
# 取钱
def withdraw(self, amount):
self.balance -= -amount
# 存钱
def deposit(self, amount):
self.balance += amount
# 查看余额
def get_balance(self):
return self.balance
# 产生两个账户
Tom = Account('Tom', 5000, Lock())
Alex = Account('Alex', 8000, Lock())
# 转账过程
def transfer(from_, to, amount):
if from_.lock.acquire(): # 锁住自己的账户
from_.withdraw(amount)
sleep(0.5)
from_.lock.release() # from账户解锁
if to.lock.acquire(): # 锁住自己的账户
to.deposit(amount) # to账户加钱
to.lock.release() # to账户解锁
print("%s给%s转账%d"%(from_.id, to.id, amount))
t1 = Thread(target = transfer, args = (Tom, Alex, 2000))
t2 = Thread(target = transfer, args = (Alex, Tom, 1000))
t1.start()
t2.start()
运行结果:
Alex给Tom转账1000
Tom给Alex转账2000
Process finished with exit code 0
1.3 案例分析
"""
模拟迅雷下载文件
一个文件放在几个不同位置 要求从每个分文件下载1/n 到一个新文件中 同步进行下载
"""
from threading import Thread, Lock
import os
lock = Lock()
urls = ['/home/tarena/桌面'] # 自定义多个路径列表
filename = input("要下载的文件:")
explorer = []
for i in urls:
if os.path.exists(i + filename):
explorer.append(i + filename)
path_num = len(explorer)
if path_num == 0:
os._exit(0)
file_size = os.path.getsize(explorer[0]) # 获得要下载文件大小
block_size = file_size//path_num # 根据需处理文件数确定一个线程下载的数量
fd = open(filename,'wb')
def load(path, num):
f = open(path, 'rb')
seek_num = block_size * (num - 1)
f.seek(seek_num)
data = f.read(block_size) # 模拟下载过程
with lock:
fd.seek(seek_num)
fd.write(data)
num = 0
jobs = []
for path in explorer:
t = Thread(target=load, args=(path, num))
jobs.append(t)
t.start()
num += 1
for i in jobs:
i.join()