转载自:
https://blog.csdn.net/ybdesire/article/details/80294638
总结:
Lock:该Lock只能被一个线程acquire一次,acquire后该Lock就处于Locked状态,必须release后才能被相同线程或其他的不同线程再次acquire一次。
RLock:该Lock可被同一线程多次acquire(如线程中含有递归或循环逻辑,递归或多次acquire该Lock),待该线程所有针对该Lock的acquire都被release后,才能被相同线程或其他的不同线程再次acquire。

首先讲解不加锁在多线程中会导致的问题,然后用实例说明如何通过加锁让函数变为线程安全的函数。也通过实例说明了RLockLock的区别:在同一线程内,对RLock进行多次acquire()操作,程序不会阻塞。

threading.Lock的用法

下面是一个python多线程的例子:

import threading

# global var
count = 0

# Define a function for the thread
def print_time(threadName):
global count

c=<span class="hljs-number">0</span>
<span class="hljs-keyword">while</span>(c&lt;<span class="hljs-number">100</span>):c+=<span class="hljs-number">1</span>count+=<span class="hljs-number">1</span>print(<span class="hljs-string">"{0}: set count to {1}"</span>.format( threadName, count) )

# Create and run threads as follows
try:
threading.Thread( target=print_time, args=(“Thread-1”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-2”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-3”, ) ).start()
except Exception as e:
print(“Error: unable to start thread”)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这个例子中,我们start了3个线程,每个线程都会对全局资源count进行改写操作。得到的结果如下,每个thread都会交替对count值进行修改。

Thread-1: set count to 198
Thread-2: set count to 199
Thread-1: set count to 200
Thread-2: set count to 201
Thread-1: set count to 202
Thread-2: set count to 203
Thread-1: set count to 204
Thread-2: set count to 205
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

由于多线程共享进程的资源和地址空间,因此,在对这些公共资源进行操作时,为了防止这些公共资源出现异常的结果,必须考虑线程的同步和互斥问题。我们可以对上例中的print_time()中访问资源的代码加锁,就可以把这个函数变为线程安全的函数。具体代码如下:

import threading

# global var
count = 0
lock = threading.Lock()

# Define a function for the thread
def print_time(threadName):
global count

c=<span class="hljs-number">0</span>
<span class="hljs-keyword">with</span> lock:<span class="hljs-keyword">while</span>(c&lt;<span class="hljs-number">100</span>):c+=<span class="hljs-number">1</span>count+=<span class="hljs-number">1</span>print(<span class="hljs-string">"{0}: set count to {1}"</span>.format( threadName, count) )

# Create and run threads as follows
try:
threading.Thread( target=print_time, args=(“Thread-1”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-2”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-3”, ) ).start()
except Exception as e:
print(“Error: unable to start thread”)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

通过threading.Lock(),就能实现加锁。这样每个thread对count进行改动期间,就不会有其它的thread插入进来改动count。得到的输出如下:

Thread-2: set count to 199
Thread-2: set count to 200
Thread-3: set count to 201
Thread-3: set count to 202
Thread-3: set count to 203
Thread-3: set count to 204
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

锁的使用,有两种方法,上面的是最简单的通过with lock来操作。

还有另一种用法,是通过Lock的acquire()release()函数来控制加锁和解锁,如下例,得到的结果和上例相同:

import threading

# global var
count = 0
lock = threading.Lock()

# Define a function for the thread
def print_time(threadName):
global count

c=<span class="hljs-number">0</span>
<span class="hljs-keyword">if</span>(lock.acquire()):<span class="hljs-keyword">while</span>(c&lt;<span class="hljs-number">100</span>):c+=<span class="hljs-number">1</span>count+=<span class="hljs-number">1</span>print(<span class="hljs-string">"{0}: set count to {1}"</span>.format( threadName, count) )lock.release()

# Create and run threads as follows
try:
threading.Thread( target=print_time, args=(“Thread-1”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-2”, ) ).start()
threading.Thread( target=print_time, args=(“Thread-3”, ) ).start()
except Exception as e:
print(“Error: unable to start thread”)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

LockRLock的区别

上例中,我们使用threading.Lock()来进行加锁。threading中还提供了另外一个threading.RLock(),那么问题来了,LockRLock有什么区别呢?

既然要讨论区别,那我们应该明白,他们的功能,大部分是相同的,很多情况下可以通用,但有细微的区别。

从原理上来说:在同一线程内,对RLock进行多次acquire()操作,程序不会阻塞。

用一个例子来说明:

import threading

lock = threading.RLock()

def f():
with lock:
g()
h()

def g():
with lock:
h()
do_something1()

def h():
with lock:
do_something2()

def do_something1():
print(‘do_something1’)

def do_something2():
print(‘do_something2’)

# Create and run threads as follows
try:
threading.Thread( target=f ).start()
threading.Thread( target=f ).start()
threading.Thread( target=f ).start()
except Exception as e:
print(“Error: unable to start thread”)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

每个thread都运行f()f()获取锁后,运行g(),但g()中也需要获取同一个锁。如果用Lock,这里多次获取锁,就发生了死锁。
但我们代码中使用了RLock。在同一线程内,对RLock进行多次acquire()操作,程序不会堵塞,所以我们可以得到如下的输出:

do_something2
do_something1
do_something2
do_something2
do_something1
do_something2
do_something2
do_something1
do_something2

RLock vs Lock相关推荐

  1. python中的Lock与RLock

    首先讲解不加锁在多线程中会导致的问题,然后用实例说明如何通过加锁让函数变为线程安全的函数.也通过实例说明了RLock和Lock的区别:在同一线程内,对RLock进行多次acquire()操作,程序不会 ...

  2. educoder 使用线程锁(lock)实现线程同步_Python并行编程(二):多线程锁机制利用Lock与RLock实现线程同步

    什么是锁机制? 要回答这个问题,我们需要知道为什么需要使用锁机制.前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享 ...

  3. python类库32[多线程同步Lock+RLock+Semaphore+Event]

    2019独角兽企业重金招聘Python工程师标准>>> 一 多线程同步 由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地 ...

  4. python线程安全的计数器_Python多线程同步Lock、RLock、Semaphore、Event实例

    一.多线程同步 由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地发挥多核cpu的资源.大部分情况都推荐使用多进程. python的多线程的 ...

  5. python 线程 的类库_python类库32[多线程同步Lock+RLock+Semaphore+Event]

    多线程基础:python类库32[多线程同步] 一 多线程同步 由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地发挥多核cpu的资源.大部 ...

  6. RLock(递归锁)

    import threading, time def run1():print("grab the first part data")lock.acquire()#进入大门后的一间 ...

  7. 搞事情 -- python之线程

    简介 操作系统线程理论 线程概念的引入背景 线程的特点 进程和线程的关系 使用线程的实际场景 用户级线程和内核级线程(了解) 线程和python 理论知识 线程的创建Threading.Thread类 ...

  8. C++ 互斥锁和条件变量实现读写锁

    最近的诸多面试经历确实让自己发现内功还不够,还需要持续的学习精进. 实现如下: class RWLock{private:int state;mutex mu;condition_variable c ...

  9. Python multiprocess 多进程模块

    转发:http://www.langzi.fun/Python multiprocess 多进程模块.html 需要注意的是,如果使用多线程,用法一定要加上if __name__=='__main__ ...

最新文章

  1. 数据统计之日活跃用户统计
  2. POJ1548最小路径覆盖
  3. java 20_java20 - 芥末小弟 - OSCHINA - 中文开源技术交流社区
  4. 计算机网络英文题库,强烈推荐计算机网络英文试题库(附答案)chapter.doc
  5. 详解varint编码原理
  6. Flask 验证模式
  7. 6点叫醒全员的腾讯是枕戈待旦,还是如李彦宏说的“新瓶装旧酒”
  8. mysql where子句 参数_MySql——使用where子句过滤数据
  9. 在 RAID 磁盘上面架构 LVM 系统
  10. (转)悟透javascript
  11. AJAX 框架Jquery的使用方法
  12. 程序员如何实现“财务自由”?反正不是靠天天加班就能的!
  13. 武汉科技大学计算机学院培养方案,武汉科技大学培养方案.DOC
  14. 大学语文复习详细资料
  15. [ArcPy] 1 ArcPy与栅格(Raster)
  16. 小姜的perl学习笔记
  17. java什么是枚举_java中的枚举到底是什么鬼
  18. 东哥java学习第二天---Java基础
  19. Erro和Exception区别Throw和Throws的区别
  20. 教你使用华为ENSP模拟器配置静态NAT(一)

热门文章

  1. 作者:陈纯(1955-),男,博士,浙江大学计算机科学与技术学院教授,中国工程院院士。...
  2. 【VB.NET】测验题目Quiz3
  3. 【Java】浅谈JavaDoc文档注释
  4. 管理软件实施(1)——什么是管理软件
  5. 使用redis批量生成主键(订单)Id
  6. iPhone失去反应咋办?
  7. 在Wireshark中过滤数据包
  8. Loopback測试软件AX1用户手冊 V3.1
  9. Excel 【小型成绩分析系统初稿】(功能及适应性有待完善)
  10. 调用discuz编辑器发布帖子显示html代码的解决办法