互斥锁解决线程共享资源冲突

互斥锁是保证线程同步共享的最简单机制,可以有效解决多线程访问共享资源冲突问题。

  • 线程共享全局变量

我们知道在不光在python,java中jvm中只有一个堆可以被所有线程所共享,而方法区也是属于堆的(保存的是类信息,常量的固定唯一不变的值)。而在Python中,全局变量也是被所有线程共享的,在共享的时候就有可能出现访问冲突。

  • 先看下面一个例子

 

import threading
import time

g_num = 0

def test1(num):
global g_num
for i in range(num):
g_num += 1
print("----这是test1, g_num is %d---"%g_num)

def test2(num):
global g_num
for i in range(num):
g_num += 1
print("----i这是test2, g_num is %d---"%g_num)

print("---线程创建之前g_num is %d---"%g_num)

t1 = threading.Thread(target=test1, args=(100,)) # 这里的后一个变量是传入一个元组
t1.start()

t2 = threading.Thread(target=test2, args=(100,))
t2.start()

while len(threading.enumerate()) != 1: # threading.enumerate()函数是统计线程个数
time.sleep(1)

print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

上面代码中的两个线程对同一个全局变量进行访问,看一下运行结果

从结果来看没有什么问题但是,我们把传递的参数换成1000000再试一下

这个时候我们发现原本结果应该是2000000,但是却并没有得到结果,这是因为当数据越大的时候,线程访问全局变量时越容易出错。

那么想要解决这个问题,于是就引入了互斥锁。

  • 互斥锁

互斥锁通俗一点说就是-->某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

  • 基本语法

在threading下的一个Lock类(注意是一个类)

 

# 创建锁
mutex = threading.Lock()

# 锁定
mutex.acquire()

# 解锁
mutex.release()

 

看语法啥也看不出来,下面对上面的例子更改一下加一下锁

 

import threading
import time

g_num = 0

def test1(num):
global g_num
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()
print("----这是test1, g_num is %d---"%g_num)

def test2(num):
global g_num
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()
print("----i这是test2, g_num is %d---"%g_num)

print("---线程创建之前g_num is %d---"%g_num)

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

p1 = threading.Thread(target=test1, args=(1000000,))
p1.start()

p2 = threading.Thread(target=test2, args=(1000000,))
p2.start()

while len(threading.enumerate()) != 1:
time.sleep(1)

print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

 

上面的代码分别对两个线程加了互斥锁,看一下运行结果

这次我们发现冲突是不是没有了

当然,我把锁加在了for循环外面如果加在内部,结果就有有点不一样了
点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00