摘要
由于多线程共享进程的资源和地址空间,因此,在对这些公共资源进行操作时,为了防止这些公共资源出现异常的结果,必须考虑线程的同步和互斥问题。
为什么加锁:1、用于非线程安全, 2、控制一段代码,确保其不产生调度混乱。
threading.Lock的用法
下面是一个python多线程的例子:
import threading
count = 0
def print_time(threadName):
global count
c=0
while(c<100):
c+=1
count+=1
print("{0}: set count to {1}".format( threadName, count) )
try:
threading.Thread( target=print_time, args=("Thread-1", ) ).start()
threading.Thread( target=print_time, args=("Thread-2", ) ).start()
threading.Thread( target=print_time, args=("Thread-3", ) ).start()
except Exception as e:
print("Error: unable to start thread")
在这个例子中,我们start了3个线程,每个线程都会对全局资源count
进行改写操作。得到的结果如下,每个thread都会交替对count值进行修改。
Thread-1: set count to 198
Thread-2: set count to 199
Thread-1: set count to 200
Thread-2: set count to 201
Thread-1: set count to 202
Thread-2: set count to 203
Thread-1: set count to 204
Thread-2: set count to 205
我们可以对上例中的print_time()中访问资源的代码加锁,就可以把这个函数变为线程安全的函数。具体代码如下:
import threading
count = 0
lock = threading.Lock()
def print_time(threadName):
global count
c=0
with lock:
while(c<100):
c+=1
count+=1
print("{0}: set count to {1}".format( threadName, count) )
try:
threading.Thread( target=print_time, args=("Thread-1", ) ).start()
threading.Thread( target=print_time, args=("Thread-2", ) ).start()
threading.Thread( target=print_time, args=("Thread-3", ) ).start()
except Exception as e:
print("Error: unable to start thread")
通过threading.Lock(),就能实现加锁。这样每个thread对count进行改动期间while(c<100)
,就不会有其它的thread插入进来改动count。得到的输出如下:
Thread-2: set count to 199
Thread-2: set count to 200
Thread-3: set count to 201
Thread-3: set count to 202
Thread-3: set count to 203
Thread-3: set count to 204
锁的使用,有两种方法,上面的是最简单的通过with lock
来操作。
还有另一种用法,是通过Lock的acquire()和release()函数
来控制加锁和解锁,如下例,得到的结果和上例相同:
import threading
count = 0
lock = threading.Lock()
def print_time(threadName):
global count
c=0
if(lock.acquire()):
while(c<100):
c+=1
count+=1
print("{0}: set count to {1}".format( threadName, count) )
lock.release()
try:
threading.Thread( target=print_time, args=("Thread-1", ) ).start()
threading.Thread( target=print_time, args=("Thread-2", ) ).start()
threading.Thread( target=print_time, args=("Thread-3", ) ).start()
except Exception as e:
print("Error: unable to start thread")
Lock与RLock的区别
在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明:
import threading
lock = threading.Lock() #Lock对象
lock.acquire()
lock.acquire() #产生了死琐。
lock.release()
lock.release()
import threading
rLock = threading.RLock() #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()
这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况
。注意:如果使用RLock
,那么acquire和release必须成对出现
,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。