Condition实现线程通信
当线程在系统中运行时,线程的调度具有一定的透明性,通常程序无法准确控制线程的轮换执行,如果有需要,Python?可通过线程通信来保证线程协调运行。
import threading class Account: # 定义构造器 def __init__(self,account_no,balance): # 封装账户编号、账户余额的两个成员变量 self.account_no = account_no self._balance = balance self.cond = threading.Condition() # 定义代表是否已经存钱的旗标 self._flag = False # 因为账户余额不允许随便修改,所以只为self._balance提供getter方法 def getBalance(self): return self._balance # 提供一个线程安全的draw()方法来完成取钱操作 def draw(self,draw_amount): # 加锁,相当于调用Condition绑定的Lock的acquire() self.cond.acquire() try: # 如果self._flag为假,表明账户中还没有人存钱进去,取钱方法阻塞 if not self._flag: self.cond.wait() else: # 执行取钱操作 print(threading.current_thread().name + " 取钱:" + str(draw_amount)) self._balance -= draw_amount print("账户余额为:" + str(self._balance)) # 将标识账户是否已有存款的旗标设为False self._flag = False # 唤醒其他线程 self.cond.notify_all() # 使用finally块来释放锁 finally: self.cond.release() def deposit(self,deposit_amount): # 加锁,相当于调用Condition绑定的Lock的acquire() self.cond.acquire() try: # 如果self._flag为真,表明账户中已有人存钱进去,存钱方法阻塞 if self._flag: # ① self.cond.wait() else: # 执行存款操作 print(threading.current_thread().name + " 存款:" + str(deposit_amount)) self._balance += deposit_amount print("账户余额为:" + str(self._balance)) # 将表示账户是否已有存款的旗标设为True self._flag = True # 唤醒其他线程 self.cond.notify_all() # 使用finally块来释放锁 finally: self.cond.release() # 定义一个函数,模拟重复max次执行取钱操作 def draw_many(account,draw_amount,max): for i in range(max): account.draw(draw_amount) # 定义一个函数,模拟重复max次执行存款操作 def deposit_many(account,deposit_amount,max): for i in range(max): account.deposit(deposit_amount) # 创建一个账户 acct = Account("1234567",0) # 创建、并启动一个“取钱”线程 threading.Thread(name="取钱者11",target=draw_many,args=(acct,800,50)).start() threading.Thread(name="取钱者12",50)).start() # 创建、并启动一个“存款”线程 threading.Thread(name="存款者1",target=deposit_many,50)).start(); threading.Thread(name="存款者2",50)).start() threading.Thread(name="存款者3",50)).start() 上面程序使用 Condition 的 wait() 和 notify_all() 方法进行控制,对存款者线程而言,当程序进入 deposit() 方法后,如果 self._flag 为 True,则表明账户中已有存款,程序调用 Condition 的 wait() 方法被阻塞;否则,程序向下执行存款操作,当存款操作执行完成后,系统将 self._flag 设为 True,然后调用 notify_all() 来唤醒其他被阻塞的线程。如果系统中有存款者线程,存款者线程也会被唤醒,但该存款者线程执行到 ① 号代码处时再次进入阻塞状态,只有执行 draw() 方法的取钱者线程才可以向下执行。同理,取钱者线程的运行流程也是如此。程序中的存款者线程循环 100 次重复存款,而取钱者线程则循环 100 次重复取钱,存款者线程和取钱者线程分别调用 Account 对象的 deposit()、draw() 方法来实现。主程序可以启动任意多个“存款”线程和“取钱”线程,可以看到所有的“取钱”线程必须等“存款”线程存钱后才可以向下执行,而“存款”线程也必须等“取钱”线程取钱后才可以向下执行。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |