Python3的threading模块 lock、Rlock的使用

摘要:
使用Python多线程提供Lock、Rlock、Semaphore、Event和Condition,以确保线程之间的同步,并确保对共享变量的多线程访问。信号量对象只能在触发某些事件或满足某些条件后才能处理数据。1锁(互斥锁)请求锁-进入锁池并等待-获取锁-锁定-释放锁(指令锁)是可用的最低级别同步指令。获取([timeout]):
Python3的threading模块 lock、Rlock的使用

一、概述

在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock 、Rlock 、Semaphore 、Event 、Condition 用来保证线程之间的同步,后者保证访问共享变量的互斥问题。

  • Lock & RLock:互斥锁,用来保证多线程访问共享变量的问题
  • Semaphore对象:Lock互斥锁的加强版,可以被多个线程同时拥有,而Lock只能被某一个线程同时拥有。
  • Event对象:它是线程间通信的方式,相当于信号,一个线程可以给另外一个线程发送信号后让其执行操作。
  • Condition对象:其可以在某些事件触发或者达到特定的条件后才处理数据

1、Lock(互斥锁)

  • 请求锁定 — 进入锁定池等待 — — 获取锁 — 已锁定— — 释放锁

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。
构造方法:mylock = Threading.Lock( )


实例方法:

  • acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。
  • release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

实例一(未使用锁):

import threading
import time

num = 0

def show(arg):
    global num
    time.sleep(1)
    num +=1
    print('bb :{}'.format(num))

for i in range(5):
    t = threading.Thread(target=show, args=(i,))  # 注意传入参数后一定要有【,】逗号
    t.start()

print('main thread stop')

--------------------------------------------------------------------------
main thread stop
bb :1
bb :2
bb :3bb :4
bb :5

实例二(使用锁)

import threading
import time

num = 0

lock = threading.RLock()


# 调用acquire([timeout])时,线程将一直阻塞,
# 直到获得锁定或者直到timeout秒后(timeout参数可选)。
# 返回是否获得锁。
def Func():
    lock.acquire()
    global num
    num += 1
    time.sleep(1)
    print(num)
    lock.release()


for i in range(10):
    t = threading.Thread(target=Func)
    t.start()
------------------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
#可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性

对于Lock对象而言,如果一个线程连续两次release,使得线程死锁。所以Lock不常用,一般采用Rlock进行线程锁的设定。

import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num 
        time.sleep(1)

        if lock.acquire(1):  
            num = num+1
            msg = self.name+' set num to '+str(num)
            print(msg)
            lock.acquire()
            lock.release()
            lock.release()
num = 0
lock = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()
------------------------------------------------------
Thread-12 set num to 1

2、RLock(可重入锁)

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
构造方法:mylock = Threading.RLock()
实例方法:acquire([timeout])/release(): 跟Lock差不多。

  • 实例解决死锁,调用相同次数的acquire和release,保证成对出现
import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()

print(rLock.acquire())
  • 详细实例:
import threading
mylock = threading.RLock()
num = 0
class WorkThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.t_name = name
    def run(self):
        global num
        while True:
            mylock.acquire()
            print('
%s locked, number: %d' % (self.t_name, num))
            if num >= 2:
                mylock.release()
                print('
%s released, number: %d' % (self.t_name, num))
                break
            num += 1
            print('
%s released, number: %d' % (self.t_name, num))
            mylock.release()
def test():
    thread1 = WorkThread('A-Worker')
    thread2 = WorkThread('B-Worker')
    thread1.start()
    thread2.start()
if __name__ == '__main__':
    test() 
--------------------------------------------------
A-Worker locked, number: 0

A-Worker released, number: 1

A-Worker locked, number: 1

A-Worker released, number: 2

A-Worker locked, number: 2

A-Worker released, number: 2

B-Worker locked, number: 2

B-Worker released, number: 2

免责声明:文章转载自《Python3的threading模块 lock、Rlock的使用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇修改 ubuntu NTFS 文件系统下没有执行权限的问题编程王道,唯“慢”不破下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

质因子分解——Prime Factors

先上原理 对于一个非素数来说有两种情况 1,所有质因子小于等于sqrt(n) 2,只存在一个大于sqrt(n)的质因子,其他质因子都小于sqrt(n) 至于证明,可以用反证法。 若是有多余一个大于sqrt(n)的质因子,这些因子的乘积..... 下面上代码 这里借助一个结构体,当然你也可以用数组 struct factor { int x;//记录...

arcpy利用XY创建点

# -*- coding: utf-8 -*-"""Created on Sun Apr 7 15:32:24 2019@author: """# XYTableToPoint.py# Description: Creates a point feature class from input table# import system modules imp...

python--GIL锁

GIL锁 本节目录 一 介绍 二 GIL介绍 三 GIL与Lock 四 GIL与多线程 五 多线程性能测试 一 背景知识 ''' 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads fr...

【Java并发基础】加锁机制解决原子性问题

前言 原子性指一个或多个操作在CPU执行的过程不被中断的特性。前面提到原子性问题产生的源头是线程切换,而线程切换依赖于CPU中断。于是得出,禁用CPU中断就可以禁止线程切换从而解决原子性问题。但是这种情况只适用于单核,多核时不适用。 以在 32 位 CPU 上执行 long 型变量的写操作为例来说明。 long 型变量是 64 位,在 32 位 CPU 上...

在Lambda表达式中进行递归调用

Lambda表达式是一个匿名的方法,在开发期我们是不知道其方法名是什么的,所以我们要怎么递归调用呢? 如果你看过我这文章《让您知道您的方法是被何“人”调用 》的话,你应该会“啊哈”的拍一下头脑,思路就出来了,没错!!就是直接用StackFrame获取当前执行的方法,然后直接Invoke即可。示例代码:     class Test    {       ...

Build.gradle 详细配置说明

apply plugin: 'com.android.application' //说明 module 的类型,com.android.application 为程序 android { compileSdkVersion 22 //编译的SDK版本 buildToolsVersion "22.0.1" //编译的 Tool...