Python 线程锁的实现

Lock 的实现

锁只有两种状态,锁定或者未锁定Lock = _allocate_lock

_allocate_lock = thread.allocate_lock

thread.allocate_lock 是用C代码实现的,代码位置 Python/thread_pthread.h

假设我们的系统支持 POSIX semaphores

首先看下 sem_init 的原型#include int sem_init(sem_t *sem, int pshared, unsigned int value);

pshared决定了这个信号量是在进程中共享还是在线程中共享。pshared 为 非零值,那么不同进程中都可以共享

pshared 为 零值,那么在当前进程的线程中共享。PyThread_type_lockPyThread_allocate_lock(void){

...    /* 申请内存 */

lock = (sem_t *)malloc(sizeof(sem_t));    if (lock) {        /*

初始化

value 为1,表明这个锁是 unlocked,被该进程的所有线程共享

*/

status = sem_init(lock,0,1);

CHECK_STATUS("sem_init");

....

}

...

}

Acquire// waitflag 默认为 trueintPyThread_acquire_lock(PyThread_type_lock lock, int waitflag){    int success;    sem_t *thelock = (sem_t *)lock;    int status, error = 0;

dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));    do {        if (waitflag)            //默认执行到这里

status = fix_status(sem_wait(thelock));        else

status = fix_status(sem_trywait(thelock));

} while (status == EINTR); /* Retry if interrupted by a signal */

if (waitflag) {

CHECK_STATUS("sem_wait");

} else if (status != EAGAIN) {

CHECK_STATUS("sem_trywait");

}

success = (status == 0) ? 1 : 0;

dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));    return success;

}

ReleasevoidPyThread_release_lock(PyThread_type_lock lock){    sem_t *thelock = (sem_t *)lock;    int status, error = 0;

dprintf(("PyThread_release_lock(%p) called\n", lock));    // sem_post 是关键,释放锁

status = sem_post(thelock);

CHECK_STATUS("sem_post");

}

RLock 的实现

RLock表示的是 reentrant lock,如果该锁已经被获取,那么acquire 可以被同一个线程(进程)多次无阻塞调用。但是 release 必须被匹配的使用。

下面可以看到 RLock 不过是一个浅包装def RLock(*args, **kwargs):

return _RLock(*args, **kwargs)

RLock 内部保存了一个普通的锁(thread.allocate_lock 生成),同时保存了 这个锁的 owner,class _RLock():

def __init__(self):

# 内部使用的 一个锁

self.__block = _allocate_lock()        # __owner 用来保存 acquire 成功时的线程 id

self.__owner = None

# acquire被重复调用的次数

self.__count = 0

python3 的实现

python3 会判断系统是否支持 reentrant lock,如果支持则用系统的,否则用 python 代码实现一个。

下面我们将看到,如何只用一个 Lock来实现其他的同步机制, Condition, Event, Semaphore等

Condition 的实现

多个线程可以用 condition 来等待同一个事件的发生,当一个事件发生后,所有等待的线程都可以得到通知。

一个 Condition 总是和一个锁关联在一起的。可以传递一个锁,也可以由 构造函数自己创建一个。

先看下如何使用import loggingimport randomimport threadingimport time

logging.basicConfig(level=logging.DEBUG,

format='(%(threadName)-9s) %(message)s',)

queue = []def consumer(cv, q):

logging.debug('Consumer thread started ...')    while True:        with cv:            while not q:

logging.debug("Nothing in queue, consumer is waiting")

cv.wait()

num = q.pop(0)

logging.debug("Consumed %s", num)

time.sleep(random.randint(1,3))def producer(cv, q):

logging.debug('Producer thread started ...')    while True:        with cv:

nums = range(5)

num = random.choice(nums)

q.append(num)

logging.debug("Produced %s", num)

cv.notify_all()if __name__ == '__main__':

condition = threading.Condition()    for i in range(10):

threading.Thread(name='consumer%s' % i, target=consumer, args=(condition, queue)).start()

pd = threading.Thread(name='producer', target=producer, args=(condition, queue))

pd.start()

下面看如何实现class _Condition:

def __init__(self, lock=None, verbose=None):

# 必须关联一个 Lock,如果没有的话,则自己创建一个 RLock

if lock is None:

lock = RLock()

self.__lock = lock        # 可以在 Condition上调用 acquire() and release() 方法,实际是调用的是内部锁的方法

self.acquire = lock.acquire

self.release = lock.release        # 如果锁定义了 _release_save _acquire_restore _is_owned 方法,那么使用之,否则用自己定义的

#......

# 这个很重要,保存了等待在这个Condition上的信息

self.__waiters = []

下面看 wait方法,为了篇幅,省略了部分代码def wait(self, timeout=None):

# 必须先成功调用acquire方法,才能调用wait

if not self._is_owned():            raise RuntimeError("cannot wait on un-acquired lock")        # 生成一个锁,并调用 acquire,使得它处于 locked 状态

# 这个锁代表一个waiter

waiter = _allocate_lock()

waiter.acquire()        # 保存起来

self.__waiters.append(waiter)

saved_state = self._release_save()        try:    # restore state no matter what (e.g., KeyboardInterrupt)

if timeout is None:                # 再次调用 acquire 方法,等待锁被释放

waiter.acquire()                if __debug__:

self._note("%s.wait(): got it", self)            else:                # 。。。。。。

finally:            # 必须恢复锁原来的状态,这个方法很重要

self._acquire_restore(saved_state)

再看下 notify方法def notify(self, n=1):

# 同样,必须得调用 acquire成功,才可以调用本方法

if not self._is_owned():            raise RuntimeError("cannot notify on un-acquired lock")

__waiters = self.__waiters

waiters = __waiters[:n]        if not waiters:            if __debug__:

self._note("%s.notify(): no waiters", self)            return

self._note("%s.notify(): notifying %d waiter%s", self, n,

n!=1 and "s" or "")        for waiter in waiters:            # 调用 锁上的 release 方法,使得等待者可以继续

waiter.release()            try:

__waiters.remove(waiter)            except ValueError:                pass

作者:zhaoxg_cat

链接:https://www.jianshu.com/p/e84b2d201b40

python 线程锁_Python线程锁的实现相关推荐

  1. python中gil锁和线程锁_Python线程——GIL锁、线程锁(互斥锁)、递归锁(RLock)...

    GIL锁 ​ 计算机有4核,代表着同一时间,可以干4个任务.如果单核cpu的话,我启动10个线程,我看上去也是并发的,因为是执行了上下文的切换,让看上去是并发的.但是单核永远肯定时串行的,它肯定是串行 ...

  2. python 判断线程状态_Python线程指南

    Python线程指南 本文介绍了Python对于线程的支持,包括"学会"多线程编程需要掌握的基础以及Python两个线程标准库的完整介绍及使用示例. 注意:本文基于Python2. ...

  3. python 线程同步_Python 线程同步

    zhoushixiong Python 线程同步 以下代码可以直观展示加锁和不加锁时,对数据修改情况. 加锁时 # -*-* encoding:UTF-8 -*- # author : shoushi ...

  4. python线程状态_Python线程

    1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在 ...

  5. python 线程退出_python线程退出

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 如果某线程并未使用很多 io 操作, 它会在自己的时间片内一直占用处理器(和 g ...

  6. python线程状态_python 线程的五个状态

    当程序中包含多个线程时,CPU 不是一直被特定的线程霸占,而是轮流执行各个线程. 那么,CPU 在轮换执行线程的过程中,即从创建到消亡的整个过程,可能会历经 5 种状态,分别是新建.就绪.运行.阻塞和 ...

  7. python 判断线程状态_Python 线程和进程

    前言 学编程,谁没有为线程折腾过啊. 目录 线程与进程 线程与进程是操作系统里面的术语,简单来讲,每一个应用程序都有一个自己的进程. 操作系统会为这些进程分配一些执行资源,例如内存空间等. 在进程中, ...

  8. python中线程同步_Python线程同步在实际应用中功能体现

    在Python编程语言中,对于线程的操作是一个比较重要的应用技术.我们将会在这篇文章中为大家详细介绍一下这方面的相关基础内容,Python线程同步的应用方式.多个执行线程经常要共享数据,如果仅仅读取共 ...

  9. python结束线程类_Python线程指南(转)

    1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在 ...

  10. python线程进程_python 线程进程

    四 线程死锁和递归锁 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去.下面 ...

最新文章

  1. python32bit改64bit,从32位Python更改64位注册表
  2. 阿里云资深总监肖力:安全智能时代公有云更靠谱
  3. 玩转以太坊(Ethereum)的测试网络
  4. 【5】CCNA课堂第一天
  5. centos7服务器搭建elasticsearch7.6.0集群
  6. linux修改jdk环境变量6,Linux CentOS 6.5 使用自带jdk修改环境变量(示例代码)
  7. 区块链风口下,开发者下海是否为时已晚?
  8. Android开发之异步消息处理机制AsyncTask
  9. 兴业银行实时跨行转入功能、免除手续费及网点排队
  10. Unity 本地化比较实用的实现方案
  11. 程序员的圣诞节是怎么样的?
  12. php能做定时关机吗,windows怎么定时关机?
  13. python爬取公众号阅读量_公众号提升阅读量!免费推荐几个互阅推广平台.
  14. MATLAB---构造一个插值三次样条曲线
  15. PictureSelector 使用
  16. 北京交通大学云平台实验虚拟机踩坑
  17. 微信小程序--实现番茄钟功能
  18. 在东北老家坐长途车的遭遇
  19. 站住!我要送你点网格智能干货
  20. 寒假算法训练1-J(分棍子,求最长棍子的数量,另外学习map的排序方法)

热门文章

  1. JAVA毕业设计Web企业客户管理系统计算机源码+lw文档+系统+调试部署+数据库
  2. 技术人生:高山仰止,景行观止,虽不能至,我心向往之
  3. m计算机代表什么意思,计算器上的m+是什么意思
  4. UE4-使用WebBrowser插件打开720云全景图
  5. vue 加载720全景图
  6. win查看服务器主板型号,Win10怎么看电脑主板型号?
  7. 机器学习笔记 - EfficientNet论文解读
  8. java分页用到的控件,laypage分页控件使用方法
  9. PHP毕业设计项目作品源码选题(13)学校排课和选课系统毕业设计毕设作品开题报告
  10. android自动修音,唱吧自动一键修音软件-唱吧自动修音app8.8.6 安卓手机版下载_东坡手机下载...