引文
上一篇博客留下了一个问题,如何解决资源抢占问题,接下来将会给出解决方法
互斥锁与死锁
互斥锁
当多个进程几乎同时修改某一个共享数据时,我们需要进行同步控制,否则会造成读脏数据
- 原理
- 当某个进程要修改共享数据时,我们先将其锁定,此时资源为“锁定”状态,其他线程不能改变,等到资源得到释放之后,才能被其他线程锁定并修改
- 互斥锁保证了每次只有一个线程进行写入操作,从而保证了在多个线程的情况下共享数据的正确性
- 代码示例
import threading import time def a(x, mutex): global num # 上锁 mutex.acquire() for i in range(x): num += 1 # 释放 mutex.release() print(f'a: {num}') def b(x, mutex): global num # 上锁 mutex.acquire() for i in range(x): num += 1 # 释放 mutex.release() print(f'b: {num}') if __name__ == '__main__': mutex = threading.Lock() num = 100 t1 = threading.Thread(target=a, args=(1000000, mutex)) t2 = threading.Thread(target=b, args=(1000000, mutex)) t1.start() t2.start() # 等待1秒,之后子线程已结束 time.sleep(1) print(num)
死锁
- 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
- 如果重复上了很多个Lock锁也会造成死锁状态
- 代码示例
import threading def a(mutex): mutex.acquire() mutex.acquire() print('a') mutex.release() mutex.release() if __name__ == '__main__': mutex = threading.Lock() t = threading.Thread(target=a, args=(mutex,)) t.start() print('main')
- 如果将Lock锁换成RLock锁,就会避免死锁问题
- 添加超时时间也可以避免死锁
注意: 程序设计时要尽量避免死锁问题
线程同步
threading里面有一个Condition类,这个类里有两个方法,分别是__enter__
和__exit__
,所以使用这个类的时候可以以with
的形式出现。使用Condition类可以实现线程同步
- 以一个简单的对话举例说明:
天猫精灵:小爱同学!
小爱同学:我在!
天猫精灵:你想去哪里?
小爱同学:我想去你的心里! - 代码示例
import threading from threading import Condition class TianMao(threading.Thread): def __init__(self, con): super().__init__(name='天猫精灵') self.con = con def run(self): with self.con: print(f"{self.name}:小爱同学!") # 唤醒 self.con.notify() # 等待 self.con.wait() print(f"{self.name}:你想去哪里?") # 唤醒 self.con.notify() class XiaoAi(threading.Thread): def __init__(self, con): super().__init__(name='小爱同学') self.con = con def run(self): with self.con: # 等待 self.con.wait() print(f"{self.name}:我在!") # 唤醒 self.con.notify() # 等待 self.con.wait() print(f"{self.name}:我想去你心里!") if __name__ == '__main__': con = threading.Condition() xiaoai = XiaoAi(con) tianmao = TianMao(con) xiaoai.start() tianmao.start()
当天猫精灵说完第一句话时,就会唤醒正在等待的小爱同学,之后天猫精灵就处于等待状态,以此循环直到对话结束
多任务版udp聊天
学了多线程,也没有用在一个实际的例子里,现在开发一款简单的多任务版udp聊天,可以同时发送信息和接收信息
- 代码示例
import socket import threading def send_info(udp_socket): while True: # 3、发送信息 content = input('请输入要发送的内容:').encode('gbk') udp_socket.sendto(content, ('192.168.1.3', 8080)) def recv_info(udp_socket): while True: # 4、接收信息 infos, addr = udp_socket.recvfrom(1024) print(f"{addr}:{infos.decode('gbk')}") def udp_chat(): # 1、创建套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 2、绑定本地ip和port udp_socket.bind(("192.168.1.3", 7890)) # 3、创建发送信息线程 t1 = threading.Thread(target=send_info, args=(udp_socket,)) # 4、创建接收信息线程 t2 = threading.Thread(target=recv_info, args=(udp_socket,)) t1.start() t2.start() if __name__ == '__main__': udp_chat()
最后,有喜欢博主写的内容的伙伴可以点赞收藏加关注哦!