使用互斥锁解决多任务之间资源竞争问题
问题的提出
当我们使用多任务编程的时候,假如多个线程对同一个变量进行调用,由于操作系统对于
各个线程调用的顺序和频率是不同的,当单核CPU执行某个线程到一半的时候,会暂停去
执行另一个线程,这个时候内存中保存的全局变量可能会与另一个线程的全局变量冲突,
造成资源的竞争。
案例一
import threading
import time
num = 0
def test1(count):
global num
for i in range(count):
num += 1
print('-----子线程1---num=%d' % num)
def test2(count):
global num
for i in range(count):
num += 1
print('-----子线程2---num=%d' % num)
def main():
t1 = threading.Thread(target=test1, args=(100,)) # 对于线程t1,传入count = 100
t2 = threading.Thread(target=test2, args=(100,))
t1.start()
t2.start()
time.sleep(1)
print('-----main进程---num=%d' % num)
if __name__ == '__main__':
main()
运行结果:
-----子线程1---num=100
-----子线程2---num=200
-----main进程---num=200
可以发现,代码运行情况符合预期结果。线程1和线程2分别对num进行了100次的加法。
然而当count改为1000000的时候。发现运行的结果不是预期的2000000
-----子线程2---num=1229194
-----子线程1---num=1228313
-----main进程---num=1228313
发生以上现象的原因就是,当CPU去执行程序的时候,并没有一次性将线程1的num+=1
这条语句执行完再去执行线程2的num+=1,这就造成了,当线程1中num+1的时候,还没
有将新的num重新赋值给num,而此时CPU已经在执行线程2,导致了线程2在运行
num+1的时候,此时的num还是未加1的值,因此,明明执行了两次num+=1,而其实此
时的num实际只加了1。并且随着count的数字越大,所造成资源竞争的概率将越大。
使用互斥锁来避免多线程之间的资源竞争问题
就好比当a在上厕所的时候,都会将厕所的门关上,然后门外的b只能等待a做完上厕所这件事,然后将门打开,b才能开始上厕所。而不是,a上到一半,b就闯进门占用a的马桶。b上到一半,a又进来抢b的马桶。
互斥锁也是这个道理,将一段代码用互斥锁进行封闭,当这段代码执行完则释放,假如发现该线程中已经被互斥锁锁住,则必须等锁释放才能执行。这样就避免了之前的资源竞争的问题。使得变量的调用在线程中有了现来后到的次序。
案例二:
import threading
import time
num = 0
mutex = threading.Lock()
def test1(count):
global num
for i in range(count):
mutex.acquire()
num += 1
mutex.release()
print('-----子线程1---num=%d' % num)
def test2(count):
global num
for i in range(count):
mutex.acquire()
num += 1
mutex.release()
print('-----子线程2---num=%d' % num)
def main():
t1 = threading.Thread(target=test1, args=(1000000,)) # 对于线程t1,传入count = 100
t2 = threading.Thread(target=test2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print('-----main进程---num=%d' % num)
if __name__ == '__main__':
main()
运行结果
-----子线程1---num=1918413
-----子线程2---num=2000000
-----main进程---num=2000000