cpython gil,CPython的线程与GIL

本文详细解析了Python中的GIL(全局解释器锁)如何在多线程环境中自动释放,重点在于未持有GIL的线程等待超时和GIL状态变化时的释放策略。通过探讨ceval.c中的关键代码,展示了何时及如何触发gil_drop_request,确保线程间的协作和公平执行。
摘要由CSDN通过智能技术生成

持有GIL的线程什么时候释放GIL?

先说结论:如果未持有GIL的线程太久没有获取GIL,已经持有GIL的线程就会释放锁。

在ceval.c#1237行中可以看到:ceval->gil_drop_request 被标记时,会释放锁。

main_loop:

for (;;) {

...

if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {  // 其他线程要求当前线程释放锁

/* Give another thread a chance */

if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {

Py_FatalError("ceval: tstate mix-up");

}

drop_gil(ceval, tstate);   // 当前线程释放锁

/* Other threads may run now */

take_gil(ceval, tstate);   // 当前线程尝试再获取锁

...

}

eval->gil_drop_request 什么时候被标记呢?

看下面的代码可以得出结论:如果 未持有GIL的线程 超过了等待时间 且 GIL是锁住的状态 且 GIL的持有者没有变更过,就会标记 ceval->gil_drop_request变量。

static void take_gil(PyThreadState *tstate)

{

...

while (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) {  // 只要 gil 是锁住的状态, 进入这个循环

int timed_out = 0;

unsigned long saved_switchnum;

saved_switchnum = _PyRuntime.ceval.gil.switch_number;   // 保存当前持有GIL的身份

// 释放 gil.mutex, 并在以下两种条件下唤醒

// 1. 等待 INTERVAL 微秒(默认 5000)

// 2. 还没有等待到 5000 微秒但是收到了 gil.cond 的信号

COND_TIMED_WAIT(_PyRuntime.ceval.gil.cond, _PyRuntime.ceval.gil.mutex,

INTERVAL, timed_out);

// 如果超过了等待时间 && GIL是锁住的状态 && GIL的持有者没有变更过

if (timed_out &&

_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&

_PyRuntime.ceval.gil.switch_number == saved_switchnum) {

SET_GIL_DROP_REQUEST();  // 把 gil_drop_request 值设为 1, 持有GIL的线程看到这个值的时候, 会尝试释放GIL

}

}

...

}

所以,当未持有GIL的线程太久没有获取GIL了,就会设置一个全局变量。当前持有GIL的线程看到全局变量后,就知道自己要释放GIL。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值