线程锁(互斥锁Mutex)
线程锁(互斥锁Mutex)
一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况?
# -*- coding:utf-8 -*-
import threading
import time
num = 100#设定一个共享变量:num=100在主线程中,我想要在子线程中修改num
def run(n):
global num#在函数里修改函数外变量,首先应该声明为全局变量,在每个线程中都获取这个全局变量
time.sleep(1)#线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行,即:此时不占用cpu,直接使这个线程挂起,cpu去干别的去了。
num -= 1#对此公共变量进行-1操作
t_objs = []#存线程实例
for i in range(100):
t = threading.Thread(target=run, args=("t-%s"%i,))
t.start()
t_objs.append(t)
for t in t_objs:
t.join()#不加join,直接就运行出的结果是个中间状态。 print('final num:', num )
#结果:('final num:', 4)
正常来讲,这个num结果应该是0, 但在python 2.7上多运行几次,会发现,最后打印出来的num结果不总是0,为什么每次运行的结果不一样呢? 哈,很简单,假设你有A,B两个线程,此时都 要对num 进行减1操作, 由于2个线程是并发同时运行的,所以2个线程很有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。
*注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁
加锁版本
# -*- coding:utf-8 -*-
import threading
import time
num = 100
def run(n):
global num
time.sleep(1)
lock.acquire() # 修改数据前加锁
num -= 1 #使中间过程变成串行
lock.release() # 修改后释放
lock = threading.Lock()#生成全局锁
t_objs = []
for i in range(100):
t = threading.Thread(target=run, args=("t-%s"%i,))
t.start()
t_objs.append(t)
for t in t_objs:
t.join() print('final num:', num )
#结果:('final num:', 0)
GIL VS Lock
机智的同学可能会问到这个问题,就是既然你之前说过了,Python已经有一个GIL来保证同一时间只能有一个线程来执行了,为什么这里还需要lock? 注意啦,这里的lock是用户级的lock,跟那个GIL没关系 ,具体我们通过下图来看一下+配合我现场讲给大家,就明白了。

那你又问了, 既然用户程序已经自己有锁了,那为什么C python还需要GIL呢?加入GIL主要的原因是为了降低程序的开发的复杂度,比如现在的你写python不需要关心内存回收的问题,因为Python解释器帮你自动定期进行内存回收,你可以理解为python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数据是可以被清空的,此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量,py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了,结果就有可能新赋值的数据被删除了,为了解决类似的问题,python解释器简单粗暴的加了锁,即当一个线程运行时,其它人都不能动,这样就解决了上述的问题, 这可以说是Python早期版本的遗留问题。
线程锁(互斥锁Mutex)的更多相关文章
- 线程锁(互斥锁Mutex)及递归锁
一.线程锁(互斥锁) 在一个程序内,主进程可以启动很多个线程,这些线程都可以访问主进程的内存空间,在Python中虽然有了GIL,同一时间只有一个线程在运行,可是这些线程的调度都归系统,操作系统有自身 ...
- 并发编程 - 线程 - 1.互斥锁/2.GIL解释器锁/3.死锁与递归锁/4.信号量/5.Event事件/6.定时器
1.互斥锁: 原理:将并行变成串行 精髓:局部串行,只针对共享数据修改 保护不同的数据就应该用不用的锁 from threading import Thread, Lock import time n ...
- JoinableQueue队列,线程,线程于进程的关系,使用线程,线程的特点,守护线程,线程的互斥锁,死锁问题,递归锁,信号量
1.JoinableQueue队列 JoinableQueue([maxsize]):这就像是一个Queue对象,但是队列允许项目的使用者通知生成者项目已经被成功处理.通知进程是使用共享的信号和条件变 ...
- Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁、信号量、事件、队列、生产者消费者模型
一.进程锁(同步锁/互斥锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 例 ...
- 并发编程---互斥锁---互斥锁与join的区别
互斥锁 互斥锁:就是把多个进程并发,修改成一块共享数据的操作变成串行,保证是一个一个来修改的. 缺点:效率低,加锁过程复杂 优点:增加了安全性 from multiprocessing import ...
- 经典线程同步 互斥量Mutex
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...
- (转)经典线程同步 互斥量Mutex
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...
- 多线程面试题系列(7):经典线程同步 互斥量Mutex
前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...
- 秒杀多线程第七篇 经典线程同步 互斥量Mutex
本文转载于:http://blog.csdn.net/morewindows/article/details/7470936 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用 ...
随机推荐
- HTML学习笔记(五)框架
框架 通过使用框架,可以在同一个浏览器窗口中显示多个页面. eg: <frameset rows="50%,50%"> <frame src="/exa ...
- E20181121-hm
invoke vt. 乞灵,祈求; 提出或授引…以支持或证明; 召鬼; 借助
- Android NDK开发指南(一) Application.mk文件
http://www.cnblogs.com/yaozhongxiao/archive/2012/03/06/2381586.html Application.mk目的是描述在你的应用程序中所需要的模 ...
- ubuntu 安装R 语言
我个人的环境是 ubuntu 12.04 64 位桌面版. 我自己在安装R 语言时,发现它依赖的库真不是一般的多,所以我在这里简单记录一下我整个安装过程 首先你需要安装 apt-get install ...
- assembly x86(nasm)修改后的日常
data segment ENG db 'SUNdayS Coming I Wanna Drive My Car,SUN,SUN$' ;9,3 sun1 db 'SUN' swcount db 0ah ...
- IDE工具、文本编辑器的列块编辑模式
前言 有时候需要对若干列进行一样的操作,比如在前一百行数据的最前边加上一样的字符,这时候可以通过列块编辑模式来快捷地实现这个效果.在列块编辑模式下,被选定的区域内的所有字符会被替换成你之后输入的字符. ...
- go系列(5)- beego自己写controller
前边的系列文章已经讲述了如何安装环境, beego的处理逻辑都是在Controller里面完成的,下面就写一个最简单的Controller. 我们在写自己的controller的时候,一定要继承bee ...
- ShareSDK集成遇到问题
解决方案
- IMG 的alt和title的区别(转自 百度空间--路云的世界)
图片标签img中alt与title的区别 图片标签img中alt与title的区别 可能很多新手在做站内优化的时候,不明白图片标签img中alt与title的区别,今天为大家说一下其中的区别. 大家可 ...
- CF #541div2 D
题目本质:形成一个拓扑图,不应带自环. 解决方法: 1.先把等于号的部分用dsu缩点: 2.大于和小于号建立拓扑关系: 3.n*m的矩阵,只要用标号n+j代表m集合的第j个就从二维降到一维了: 4.d ...