"_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_DFL" 或
   "signal.SIG_IGN")，则此函数将不做任何操作。

   在 3.10 版本发生变更: 添加了 *signum* 参数来定制信号的编号。

   备注:

     这并不会发出对应的信号而是将一个调用排入关联处理器的计划任务（如
     果句柄存在的话）。 如果你想要真的发出信号，请使用
     "signal.raise_signal()"。

_thread.exit()

   抛出 "SystemExit" 异常。如果没有捕获的话，这个异常会使线程退出。

_thread.allocate_lock()

   返回一个新的锁对象。锁中的方法在后面描述。初始情况下锁处于解锁状态
   。

_thread.get_ident()

   返回当前线程的 “线程标识符”。它是一个非零的整数。它的值没有直接含义
   ，主要是用作 magic cookie，比如作为含有线程相关数据的字典的索引。线
   程标识符可能会在线程退出，新线程创建时被复用。

_thread.get_native_id()

   返回内核分配给当前线程的原生集成线程 ID。 这是一个非负整数。 它的值
   可被用来在整个系统中唯一地标识这个特定线程（直到线程终结，在那之后
   该值可能会被 OS 回收再利用）。

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

   Added in version 3.8.

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

_thread.stack_size([size])

   返回创建线程时使用的堆栈大小。可选参数 *size* 指定之后新建的线程的
   堆栈大小，而且一定要是0（根据平台或者默认配置）或者最小是
   32,768(32KiB)的一个正整数。如果 *size* 没有指定，默认是0。如果不支
   持改变线程堆栈大小，会抛出 "RuntimeError" 错误。如果指定的堆栈大小
   不合法，会抛出 "ValueError" 错误并且不会修改堆栈大小。32KiB是当前最
   小的能保证解释器有足够堆栈空间的堆栈大小。需要注意的是部分平台对于
   堆栈大小会有特定的限制，例如要求大于32KiB的堆栈大小或者需要根据系统
   内存页面的整数倍进行分配 - 应当查阅平台文档有关详细信息（4KiB页面比
   较普遍，在没有更具体信息的情况下，建议的方法是使用4096的倍数作为堆
   栈大小）。

   可用性: Windows, pthreads。

   带有 POSIX 线程支持的 Unix 平台。

_thread.TIMEOUT_MAX

   "Lock.acquire" 的 *timeout* 形参所允许的最大值。 指定大于该值的
   timeout 将引发 "OverflowError"。

   Added in version 3.2.

锁对象有以下方法：

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

   没有任何可选参数时，该方法无条件申请获得锁，有必要的话会等待其他线
   程释放锁（同时只有一个线程能获得锁 —— 这正是锁存在的原因）。

   如果提供了 *blocking* 参数，具体的行为将取决于它的值：如果它为假值
   ，则只在能够立即获取到锁而无需等待时才会获取，而如果它为真值，则会
   与上面一样无条件地获取锁。

   如果提供了浮点数形式的 *timeout* 参数且为正值，它将指明在返回之前的
   最大等待秒数。 负的 *timeout* 参数表示无限期的等待。 如果
   *blocking* 为假值则你不能指定 *timeout*。

   如果成功获取到所会返回 "True"，否则返回 "False"。

   在 3.2 版本发生变更: 新的 *timeout* 形参。

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

lock.release()

   释放锁。锁必须已经被获取过，但不一定是同一个线程获取的。

lock.locked()

   返回锁的状态：如果已被某个线程获取，返回 "True"，否则返回 "False"。

除了这些方法之外，锁对象也可以通过 "with" 语句使用，例如：

   import _thread

   a_lock = _thread.allocate_lock()

   with a_lock:
       print("在执行这段代码时，a_lock 已被锁定")

**注意事项：**

* 线程与中断奇怪地交互："KeyboardInterrupt" 异常可能会被任意一个线程捕
  获。（如果 "signal" 模块可用的话，中断总是会进入主线程。）

* 调用 "sys.exit()" 或是抛出 "SystemExit" 异常等效于调用
  "_thread.exit()"。

* 不可能中断锁上的 "acquire()" 方法 --- "KeyboardInterrupt" 异常将在获
  取锁之后发生。

* 当主线程退出时，由系统决定其他线程是否存活。在大多数系统中，这些线程
  会直接被杀掉，不会执行 "try" ... "finally" 语句，也不会执行对象析构
  函数。

* 当主线程退出时，不会进行正常的清理工作（除非使用了 "try" ...
  "finally" 语句），标准 I/O 文件也不会刷新。
