python threading.Lock() 多线程锁

示例

import threading

# 定义全局变量
import time

g_num = 0

class SingletonData(object):
	_instance_lock = threading.Lock()

	def __new__(cls, *args, **kwargs):
		if not hasattr(SingletonData, "_instance"):
			with SingletonData._instance_lock:
				if not hasattr(SingletonData, "_instance"):
					SingletonData._instance = object.__new__(cls)

		return SingletonData._instance

	def __init__(self,):
		pass


mysingleton = SingletonData()
# 循环一次给全局变量加1
def sum_num1(num):
	global g_num
	for i in range(100000):

		lock = mysingleton._instance_lock
		flag = lock.acquire(True,)
		print("{} num:{} flag:{}".format("sum_num1",g_num,flag))
		if flag:

			g_num += 1
			lock.release()
		else:
			print("*"*50)

	print("sum1:{}::".format(num), g_num)

def sum_num3(num):
	global g_num
	for i in range(100000):

		lock = mysingleton._instance_lock
		flag = lock.acquire(True,)
		print("{} num:{} flag:{}".format("sum_num3", g_num, flag))
		if flag:

			time.sleep(0.00000002)
			g_num += 1
			lock.release()

	print("sum1:{}::".format(num), g_num)

# 循环一次给全局变量加1
def sum_num2(mnum):
	for i in range(1000000):
		global g_num
		g_num += 1
	print("sum2:", g_num)


if __name__ == '__main__':
	# 创建两个线程
	first_thread = threading.Thread(target=sum_num1,args=(1,))
	second_thread = threading.Thread(target=sum_num3,args=(2,))

	# 启动线程
	first_thread.start()
	# 启动线程
	second_thread.start()
	print(g_num)

acquire() 方法参数 blocking timeout

语法

 acquire( blocking=True, timeout=-1)

blocking

阻塞 :这是一个可选参数,用作阻塞标志。 如果将其设置为True,则如果其他某个线程持有该标志,则调用线程将被阻塞,并且一旦释放该锁,则调用线程将获取该锁并返回True。 如果将其设置为False,则如果其他线程已经获取了锁,它将不会阻塞线程,并且将返回False。 其默认值为True。

timeout

timeout :这是一个可选参数,它指定如果其他某种方法当前正在获取锁,则阻塞调用线程的秒数。 它的默认值是-1,表示线程将无限期地阻塞,直到获得锁为止。

多线程同时操作一个资源 可能会造成混乱

import threading

num = 0
def add1(th):
	i = 0
	while i <500000:
		global num
		num +=1
		i+=1
	print("th{}:".format(th),num)



t1 = threading.Thread(target=add1,args=(1,))
t1.start()
t2 = threading.Thread(target=add1,args=(2,))
t2.start()

运行

th1: 590878
th2: 706512

最终结果不为1000000 错误原因

错误分析:

两个线程first_thread和second_thread都要对全局变量g_num(默认是0)进行加1运算,但是由于是多线程同时操作,有可能出现下面情况:

在g_num=0时,first_thread取得g_num=0。此时系统把first_thread调度为”sleeping”状态,把second_thread转换为”running”状态,t2也获得g_num=0
然后second_thread对得到的值进行加1并赋给g_num,使得g_num=1
然后系统又把second_thread调度为”sleeping”,把first_thread转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
这样导致虽然first_thread和first_thread都对g_num加1,但结果仍然是g_num=1

全局变量数据错误的解决办法:

线程同步: 保证同一时刻只能有一个线程去操作全局变量 同步: 就是协同步调,按预定的先后次序进行运行。如:你说完,我再说, 好比现实生活中的对讲机

线程同步的方式:

1.线程等待(join)
2. 互斥锁

线程等待(join)

import threading

num = 0
def add1(th):
	i = 0
	while i <500000:
		global num
		num +=1
		i+=1
	print("th{}:".format(th),num)



first_thread = threading.Thread(target=add1,args=(1,))
first_thread.start()
# todo join 会使主线程等待第一个线程执行完成以后代码再继续执行,让其执行第二个线程
# todo 线程同步: 一个任务执行完成以后另外一个任务才能执行,同一个时刻只有一个任务在执行
first_thread.join()
second_thread = threading.Thread(target=add1,args=(2,))
second_thread.start()

运行结果

th1: 500000
th2: 1000000

猜你喜欢

转载自blog.csdn.net/weixin_37989267/article/details/111618401