互斥锁解决多线程资源竞争问题

如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确,
程序示例:

import threading
import time
num1 = 0
def demo1(a):
    global num1
    for i in range(a):
        num1 += 1 
    print("在demo1中,num1的值为:",num1)
def demo2(a):
    global num1
    for i in range(a):
        num1 += 1 
    print("在demo2中,num1的值为:",num1)
def main():
    nums = 1000000
    t1 = threading.Thread(target = demo1, args=(nums,))
    t2 = threading.Thread(target = demo2, args=(nums,))
    t1.start()
    t2.start()
    # 主线程等待两个子线程执行完毕
    time.sleep(5)
    print("在main中,num1的值为:",num1)
if __name__ == '__main__':
    main()

程序执行结果:
互斥锁解决多线程资源竞争问题_第1张图片
理论上 num1经过两个线程自加nums = 1000000次,最后应该得到num1 =2000000,可以看出这并不是我们预料到的结果,出现了严重的偏差,两个线程互相对num1进行加一赋值操作造成结果混乱,这就是多线程的资源竞争问题。

那么,如何解决资源竞争问题?
当存在多个线程或者进程同时调用一个全局变量资源,并且会对它进行修改时,可以采用上锁这个方法,来解决资源竞争问题。采用全局变量锁,每当线程调用全局变量时,就将该资源上锁,不允许被调用,只有当调用结束后才打开锁,这里引入互斥锁,能够保证全局变量资源的安全。

互斥锁的定义:当在请求之前,资源没有被上锁,那么请求并不会堵塞;如果在请求之前,是被锁上的, 那么请求就处于一个堵塞状态,只有当前得锁被打开之后,才能再次上锁。

互斥锁格式:

# 创建锁
mutex = threading.Lock()

# 锁定
mutex.acquire()

# 释放
mutex.release()

针对以上问题,咱们试着用互斥锁解决,只需要将num1 += 1 锁住保持原子性就可以了,最后提一点:锁住的代码越少越好,,改善程序如下:

import threading
import time
num1 = 0


def demo1(a):
    
    global num1
    for i in range(a):
        lock_1.acquire() # 上锁
        num1 += 1 # 锁住 保持原子性
        lock_1.release() # 开锁
    print("在demo1中,num1的值为:",num1)


def demo2(a):

    global num1
    for i in range(a):
        lock_1.acquire() # 上锁
        num1 += 1 # 锁住 保持原子性
        lock_1.release() # 开锁
    print("在demo2中,num1的值为:",num1)
    # lock_1.release()  # 开锁

# 创建一个互斥锁,,默认是不上锁的状态
lock_1 = threading.Lock()


def main():
    nums = 1000000
    t1 = threading.Thread(target = demo1, args=(nums,))
    t2 = threading.Thread(target = demo2, args=(nums,))
    t1.start()
    t2.start()
    # 主线程等待两个子线程执行完毕
    time.sleep(2)
    print("在main中,num1的值为:",num1)


if __name__ == '__main__':
    main()



执行结果:
互斥锁解决多线程资源竞争问题_第2张图片
可以看出,虽然有一个线程结果并不理想,但已经很接近了,用互斥锁改善了很多,实际上我们最后需要的就是main里的结果,只需要保证最后我们需要的结果是正确的就行了。

互斥锁解决资源竞争的好处:互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
互斥锁的优缺点:

优点:确保了某段关键代码只能由一个线程从头到尾完整地执行。
缺点:阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁.

你可能感兴趣的:(网络编程)