python-线程同步 作者:马育民 • 2019-02-22 14:22 • 阅读:10205 # 概述 通过 [python-多线程修改公共变量引发的血案](http://www.malaoshi.top/show_1EF2qKOtyKA8.html "python-多线程修改公共变量引发的血案") 可见,多线程修改公共变量时,会引发bug,为了解决bug,要用到线程同步 在多线程修改公共变量时,如下图: [![](http://www.malaoshi.top/upload/0/0/1EF2qLeEhmkk.png)](http://www.malaoshi.top/upload/0/0/1EF2qLeEhmkk.png) 1. 第一步,先让一个线程读变量num的值 注意:具体是哪个线程不一定,由操作系统调度,图中由 **线程1** 执行 2. 第二步,让该线程计算后将值写入内存 3. 第三步,然后让另一个线程读变量num的值 4. 第四步,让该线程计算后将值写入内存 ### 临界资源 某些公共资源只能一个线程访问操作,这样的资源称为临界资源(互斥资源,共享变量) 如:上面的商品数量、票号,或者打印机 ### 临界区 访问临界资源的那段代码称为临界区 如:上面访问商品数量、票号的代码 ### 线程互斥 由于多线程要共享资源,而有些资源需要互斥使用,因此各线程间竞争使用这些资源 如:多线程修改公共变量,多线程访问打印机等 ### 线程同步 多线程访问操作公共资源时,需要多个线程有顺序的执行,互相合作、互相等待,共同完成一项任务。 一般来说,同步往往包含互斥 ### 使用互斥锁 为了实现多线程同步和互斥,python提出互斥锁 当一个线程申请互斥锁后,就只有该线程运行,其他线程都阻塞,直到该线程释放锁时,其他线程才会继续执行 由此可见,申请互斥锁和释放互斥锁之间的代码,只有一个线程在运行,所以互斥锁不要滥用,否则会导致多线程效率低下 # Lock类的使用说明 threading模块中定义了Lock类,实现互斥锁,让线程同步 注意:当 多个线程 **修改** 公共变量时,才需要互斥锁 ### 创建锁 ``` lock=threading.Lock() ``` ### 获得锁 表示之后的代码全部被锁定,只能一个线程执行 ``` lock.acquire([blocking=True,timeout=-1]) ``` **参数:** - blocking:为True,表示当前线程会阻塞,直到获得锁为止。 False,当前线程不会阻塞,直接返回false 默认为True - timeout:当blocking为True时有意义,表示n秒后返回false ### 释放锁 表示之后的代码,多线程都可以同时执行 ``` lock.release() ``` # 改造之前的代码 ``` #coding=utf-8 import threading def modify(): global num global lock #获得锁,之后的代码只能有一个线程执行,具体是哪个线程不一定,由os调度 lock.acquire() t=threading.current_thread() #获取当前线程对象 t=threading.current_thread() for index in range(100000): num+=1 print('%s,num=%d'%(t.name,num)) #释放锁,之后的代码可以多线同时执行 lock.release() if __name__ == "__main__": num=0 #创建锁 lock=threading.Lock() #创建线程,此线程修改全局变量 t=threading.Thread(target=modify) #创建线程,此线程打印全局变量 t2=threading.Thread(target=modify) #启动线程 t.start() t2.start() #阻塞 t.join() t2.join() print('执行结束,num=%d'%(num)) ``` # 改造卖火车票代码 ``` #coding=utf-8 import threading import time import os #票总数 count=500 #窗口数量 windownum=3 #初始化票号码 num=1 def sell(index): global num,lock print('%d号售票口-开始售票,票号:%d'%(index,num)) #修改变量 while True: lock.acquire() if num<=count:#本行代码是临界区,要在上面加锁 print('%d号售票口-售出票号:%d'%(index,num)) i=num+1 # time.sleep(0.00001) num=i print('%d号售票口-下一票号:%d'%(index,num)) lock.release() else: print('%d号售票口-售罄'%(index)) lock.release() break if __name__ == "__main__": lock=threading.Lock() stime=time.time() ts=[] for index in range(windownum): t=threading.Thread(target=sell,args=(index,)) ts.append(t) for item in ts: item.start() for index in ts: item.join() #主进程打印值 print('主进程,num=%s'%num) etime=time.time() print(etime-stime) ``` 原文出处:http://malaoshi.top/show_1EF2qLiQcAfn.html