_thread — 底层线程 API


此模块提供了用于处理多个线程(也称为 轻量级进程任务)的底层原语 — 多个控制线程共享其全局数据空间。为了实现同步,提供了简单的锁(也称为 互斥锁二进制信号量)。threading 模块在些模块之上构建了一个更易于使用和更高级的线程 API。

在 3.7 版本发生变更: 该模块曾经是可选的,现在总是可用。

该模块定义了下列常量和函数:

exception _thread.error

在线程特定错误时引发。

在 3.3 版本发生变更: 现在是内置 RuntimeError 的同义词。

_thread.LockType

这是锁对象的类型。

_thread.start_new_thread(function, args[, kwargs])

启动一个新线程并返回其标识符。线程执行函数 function 并附带参数列表 args(必须是元组)。可选的 kwargs 参数指定一个关键字参数字典。

当函数返回时,线程会静默地退出。

当函数因未处理的异常而终止时,将调用 sys.unraisablehook() 来处理该异常。钩子参数的 object 属性是 function。默认情况下,会打印堆栈回溯,然后线程退出(但其他线程会继续运行)。

当函数引发 SystemExit 异常时,它会被静默地忽略。

引发一个 审计事件 _thread.start_new_thread,附带参数 function, args, kwargs

在 3.8 版本发生变更: 现在使用 sys.unraisablehook() 来处理未处理的异常。

_thread.interrupt_main(signum=signal.SIGINT, /)

模拟在主线程中接收到信号的效果。一个线程可以使用此函数来中断主线程,但不能保证中断会立即发生。

如果给出 signum,则为要模拟的信号编号。如果未给出 signum,则模拟 signal.SIGINT

如果给定的信号未被 Python 处理(即它被设置为 signal.SIG_DFLsignal.SIG_IGN),此函数将不执行任何操作。

在 3.10 版本发生变更: 添加 signum 参数以自定义信号编号。

备注

这不会发出相应的信号,而是安排调用相关的处理程序(如果存在)。如果你想真正地发出信号,请使用 signal.raise_signal()

_thread.exit()

引发 SystemExit 异常。当未被捕获时,这将导致线程静默地退出。

_thread.allocate_lock()

返回一个新的锁对象。锁的方法将在下面描述。锁最初处于未锁定状态。

_thread.get_ident()

返回当前线程的“线程标识符”。这是一个非零整数。它的值没有直接含义;它旨在用作一个魔术 cookie,例如用于索引一个线程特定数据的字典。当一个线程退出并创建另一个线程时,线程标识符可能会被回收。

_thread.get_native_id()

返回由内核分配的当前线程的原生整数线程 ID。这是一个非负整数。它的值可用于在系统范围内唯一地标识这个特定的线程(直到线程终止,之后该值可能会被操作系统回收)。

可用性: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD, GNU/kFreeBSD.

在 3.8 版本加入。

在 3.13 版本发生变更: 增加了对 GNU/kFreeBSD 的支持。

_thread.stack_size([size])

返回创建新线程时使用的线程堆栈大小。可选的 size 参数指定了后续创建线程时要使用的堆栈大小,必须是 0(使用平台或配置的默认值)或一个至少为 32,768 (32 KiB) 的正整数值。如果未指定 size,则使用 0。如果不支持更改线程堆栈大小,则会引发 RuntimeError。如果指定的堆栈大小无效,则会引发 ValueError 并且堆栈大小不会被修改。32 KiB 是目前支持的最小堆栈大小值,以保证解释器本身有足够的堆栈空间。请注意,某些平台可能对堆栈大小的值有特殊限制,例如要求最小堆栈大小 > 32 KiB 或要求按系统内存页大小的倍数进行分配 — 应参考平台文档以获取更多信息(4 KiB 页面很常见;在没有更具体信息的情况下,建议使用 4096 的倍数作为堆栈大小)。

可用性: Windows, pthreads。

支持 POSIX 线程的 Unix 平台。

_thread.TIMEOUT_MAX

Lock.acquiretimeout 参数允许的最大值。指定大于此值的超时将引发 OverflowError

在 3.2 版本加入。

锁对象有以下方法:

lock.acquire(blocking=True, timeout=-1)

不带任何可选参数时,此方法无条件地获取锁,必要时会等待直到它被另一个线程释放(同一时间只有一个线程可以获取锁 — 这就是它们存在的理由)。

如果存在 blocking 参数,则操作取决于其值:如果为 false,则仅当可以立即获取锁而无需等待时才获取锁;如果为 true,则如上所述无条件地获取锁。

如果存在浮点数 timeout 参数且为正数,它指定了返回前最长的等待时间(秒)。负的 timeout 参数指定了无限期等待。如果 blocking 为 false,则不能指定 timeout

如果成功获取锁,返回值为 True,否则为 False

在 3.2 版本发生变更: 新增 timeout 参数。

在 3.2 版本发生变更: 在 POSIX 上,锁的获取现在可以被信号中断。

在 3.14 版本发生变更: 在 Windows 上,锁的获取现在可以被信号中断。

lock.release()

释放锁。锁必须是先前已经获取的,但不一定是由同一个线程获取。

lock.locked()

返回锁的状态:如果已被某个线程获取,则为 True,否则为 False

除了这些方法,锁对象还可以通过 with 语句使用,例如:

import _thread

a_lock = _thread.allocate_lock()

with a_lock:
    print("a_lock is locked while this executes")

注意事项

  • 中断总是发送到主线程(KeyboardInterrupt 异常将由该线程接收)。

  • 调用 sys.exit() 或引发 SystemExit 异常等同于调用 _thread.exit()

  • 当主线程退出时,其他线程是否存活是由系统定义的。在大多数系统上,它们会被杀死,而不会执行 try ... finally 子句或执行对象析构函数。