# encoding: UTF-8 import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) num = num+1 msg = self.name+' set num to '+str(num) print msg num = 0 def main(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': main()
此示例程序跑出来的结果是:
Thread-5 set num to 2
Thread-3 set num to 3
Thread-2 set num to 5
Thread-1 set num to 5
Thread-4 set num to 4
(为了方便展示,选用了12345为序号)
由于没有对资源进行互斥访问,造成了多个线程对资源进行“非安全”操作,所以得到了上面不可预期的结果。
为了解决上述问题,当多个线程对同一数据进行共享的时候,需要进行同步控制。python中也有类似java中的互斥锁,对访问资源的线程进行上锁,只允许当前线程对该资源进行操作,其他线程等待。
threading模块中定义了Lock类,可以方便的处理锁定:
#创建锁 mutex = threading.Lock() #锁定时长为timeout mutex.acquire([timeout]) #释放 mutex.release()
加入互斥锁即可达到我们想要的效果:依次对资源进行访问修改
import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) #对访问资源的线程进行上锁 if mutex.acquire(1): num = num+1 msg = self.name+' set num to '+str(num) print msg #对锁释放 mutex.release() #初始化计数器 num = 0 #初始化线程的锁 mutex = threading.Lock() def main(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': main()
可以达到我们的预期效果:
Thread-3 set num to 1
Thread-4 set num to 2
Thread-5 set num to 3
Thread-2 set num to 4
Thread-1 set num to 5
注:
一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”。
直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。