You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux下使用GDB释放Python线程Lock或Futex?

用GDB释放Python线程Lock解决死锁的方法

一、解决程序立即死锁无法调试的问题

程序启动后快速进入死锁,没法设置断点,有两种简单解决方案:

方法1:修改脚本增加调试窗口

在脚本的main函数末尾(线程start之后)添加暂停逻辑,给你足够时间附加GDB:

if __name__ == '__main__':
    print(os.getpid())

    thread1 = threading.Thread(target=func1, args=['thread1',])
    thread2 = threading.Thread(target=func2, args=['thread2',])
    thread1.start()
    thread2.start()
    # 添加这行,程序会等待输入后再继续
    input("Attach GDB now, then press Enter to proceed...")

运行脚本后,控制台会打印PID,此时程序暂停,你可以用sudo gdb -p <PID>附加调试。

方法2:用GDB启动程序并提前设断点

直接用GDB启动Python脚本,提前在死锁前的代码行设置断点:

gdb --args python3 m4.py

在GDB交互界面中,设置断点到func1尝试获取lock2之前的行(对应脚本第12行左右):

(gdb) b m4.py:12
(gdb) run

程序会在断点处暂停,此时你可以继续调试,或执行continue让程序运行到接近死锁的状态,再手动暂停(Ctrl+C)。

二、通过GDB解锁Futex的具体步骤

Python的threading.Lock底层基于Linux Futex实现,你可以直接通过GDB调用Futex系统调用唤醒阻塞线程,或操作Python Lock对象本身释放锁。

步骤1:定位Lock对应的Futex地址

附加GDB后,切换到主线程,用GDB的Python扩展获取全局lock1和lock2的底层Futex地址:

(gdb) thread 1
(gdb) python
import gdb
# 获取lock1的底层锁信息
lock1 = gdb.parse_and_eval("lock1")
py_lock1 = lock1["_lock"]
futex_lock1 = py_lock1["lock"]
print(f"lock1 对应的Futex地址: {futex_lock1}")

# 获取lock2的底层锁信息
lock2 = gdb.parse_and_eval("lock2")
py_lock2 = lock2["_lock"]
futex_lock2 = py_lock2["lock"]
print(f"lock2 对应的Futex地址: {futex_lock2}")
end

对比输出的地址和info threads中的futex_word,就能对应上哪个线程在等待哪个锁。

步骤2:调用Futex系统调用唤醒线程

在x86_64 Ubuntu 18.04中,SYS_futex的系统调用号是202,FUTEX_WAKE的操作码是1。调用该系统调用唤醒等待目标Futex的线程:

# 替换成你要解锁的Futex地址,比如lock2对应的地址0x1bc3fc0
(gdb) call syscall(202, 0x1bc3fc0, 1, 0, 0, 0, 0)

执行后,该Futex上阻塞的1个线程会被唤醒。

步骤3:验证解锁效果

执行continue让程序继续运行:

(gdb) continue

此时你会看到其中一个线程执行到DEADLOCK: This line will never run.的打印,说明死锁已被解除。

三、替代方案:直接调用Python Lock的release方法

如果你更倾向于操作Python对象本身,可以通过GDB的Python扩展调用Lock的release方法:

(gdb) thread 1
(gdb) python
import gdb
# 获取lock1对象并调用release
lock1 = gdb.parse_and_eval("lock1")
release_func = lock1["release"]
# 调用release方法,传入self参数
gdb.execute(f"call ((void (*)(PyObject*)){release_func})((PyObject*){lock1})")
end

此方法直接操作Python层面的锁,不需要关注底层Futex细节,但需要确保GDB的Python环境与目标程序版本兼容。

注意事项

  • 所有操作仅用于个人研究,生产环境禁止使用此类暴力解锁手段,会破坏程序状态一致性。
  • 调用PyThread_release_lock时需传递PyThread_type_lock的地址(而非Futex地址),否则会触发段错误,正确参数可通过步骤1中的py_lock1获取。

内容的提问来源于stack exchange,提问作者Jacob Quisenberry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:04:59