day 0807 多线程—共享全局变量问题
多线程—共享全局变量问题
多线程可能遇到的问题
假设有两个线程t1,t2假设都要对一个全局变量g_num进行运算,两个线程t1和t2分别对g_num各加10次,g_num的最终结果
import threading import time g_num=0 def work1(num): global g_num for i in range(num): g_num+=1 print('---in work1,g_num is %d---'% g_num) def work2(num): global g_num for i in range(num): g_num+=1 print('---in work2,g_num is %d---'% g_num) print('----线程创建之前g_num:%d'% g_num) t1=threading.Thread(target=work1,args=(10,)) t2=threading.Thread(target=work2,args=(10,)) t1.start() t2.start() while len(threading.enumerate()) !=1: time.sleep(1) print('2个线程对同一个变量的最终结果:',g_num)
----线程创建之前g_num:0
—in work1,g_num is 10—
—in work2,g_num is 20—
2个线程对同一个变量的最终结果: 20
- 理论上来讲
在num=0时,t1取得num=0,此时系统把t1调度为‘sleeping’的状态,t2准换为‘running’的状态,t2也获得num=0。然后,t2对得到的值进行加1并赋给num。num=1,然后系统又将t2调度为‘sleeping’的状态,把t1转换为‘running‘,线程t1又把它之前得到的0加1后赋值给num.这种情况,明明俩线程都完成了一个次工作,但结果还是num=1
- 实际上
因为电脑运行速度过快,t2还来不及与t1进行线程切换,t1就运行完了,如果将10改为1000000,会发现
----线程创建之前g_num:0
—in work1,g_num is 1144345—
—in work2,g_num is 1195423—
2个线程对同一个变量的最终结果: 1195423
两条线程由于共享资源,会对资源产生竞争,导致数据结果不正确
同步
同步,就是协同步调,按照预定的先后次序进行运行。好比说相声,一个说完,另外一个人再说。
进程和线程同步,可以理解为进程或者线程A和B一块配黑,A执行一定程度时需要依赖B的某个结果,于是停下来,让B运行,B开始运行,再将结果给A,A再继续操作,如此往复,直至程序结束。
计算错误的解决
通过’线程同步’来进行解决
思路:
- 系统调度t1,获取num=0,此时上一把锁,即不允许其他线程操作num
- 对num的值加1
- 解锁,此时num的值为1,其他的线程就可以使用num了,此时num=1
- 同理,其他线程也先上锁,处理完后再解锁。不允许其他线程访问,保证数据的正确性。
互斥锁
当多个线程几乎同时修改某个共享数据时,需要进行同步控制。
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制就是引入互斥锁。
互斥锁为我们的资源引入一个状态: 锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时资源状态为锁定,其他线程不能对其更改;直到该线程释放资源,资源状态变为’非锁定‘状态,其他线程才能再次锁定该资源。
互斥锁,保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
在threading模块里,定义了Lock()类,可以方便的处理锁定。
mutex = threading.Lock() #创建 mutex.acquire([blocking]) #锁定 mutex.release()#释放
- blocking True,则当前线程堵塞,直到获取这个锁为止(如未指定,则默认为True)
- False,则当前线程不被堵塞,
import threading import time g_num=0 def work1(num): global g_num for i in range(num): if mutex.acquire(True): g_num+=1 mutex.release() print('---in work1,g_num is %d---'% g_num) def work2(num): global g_num for i in range(num): if mutex.acquire(True): g_num += 1 mutex.release() print('---in work2,g_num is %d---'% g_num) print('----线程创建之前g_num:%d'% g_num) mutex=threading.Lock() t1=threading.Thread(target=work1,args=(1000000,)) t2=threading.Thread(target=work2,args=(1000000,)) t1.start() t2.start() while len(threading.enumerate()) !=1: time.sleep(1) print('2个线程对同一个变量的最终结果:',g_num)
----线程创建之前g_num:0
—in work1,g_num is 1917539—
—in work2,g_num is 2000000—
2个线程对同一个变量的最终结果: 2000000
死锁
在线程间共享多个资源时,如果两个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁。说相声两个人都等对面的先说话然后都不说话,就很尴尬。
死锁一般很少发生,但一旦发生就会造成应用停止响应。
生产消费者问题
也就是有限缓冲问题,是一个多线程同步的经典案例
描述一个两个固定大小缓冲区的线程-即所谓的“生产者”和消费者 在实际运行时会发生的问题。
生产者的主要作用,生成一定量的数据放在缓冲区中,然后,重复此过程。与此同时,消费者也在缓冲区消耗这些数据
整个问题的关键是,生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据。
解决办法
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形
1.队列,先进先出
2.栈,先进后出
Python中queue(py3)(py2,Queue),模块提供了一个同步的,线程安全的队列类,包括先入先出(FIFO)队列Queue,和后入先出(LIFO)队列LifoQueue和优先级队列PriorityQueue.
这些队列实现了锁原语(原子操作,要么不做,要么做完),可以在线程中直接使用
可以使用队列来实现线程间的同步
FIFO队列实现生产者消费者问题
- Java多线程共享全局变量问题
- java多线程全局变量共享问题
- 【python】多线程共享全局变量问题
- 关于全局变量,如何被多个.c文件共享问题
- 关于全局变量,如何被多个.c文件共享问题
- 谈谈多线程-共享全局变量.. (全是上好干货 )
- 多线程中的使用共享变量的问题
- linux动态链接库全局变量共享问题&DLL共享数据段
- 多线程-共享全局变量(python版)
- 关于全局变量,如何被多个.c文件共享问题
- 由一个多线程共享Integer类变量问题引起的。。。
- 关于进程和线程对于全局变量共享的问题学习总结
- linux动态链接库全局变量共享问题&DLL共享数据段
- 由一个多线程共享Integer类变量问题引起的。。。
- 了解动态链接(三)—— 共享模块的全局变量问题
- 静态库和动态库里的全局变量(或类的静态成员变量)共享和独立的问题
- 用关中断和互斥量来保护多线程共享的全局变量
- 多线程学习之一:线程对共享全局变量的访问
- python多线程-共享全局变量
- 关于多线程变量共享问题_改进