17.9. "_thread" —— 底层多线程 API
*********************************

======================================================================

该模块提供了操作多个线程（也被称为 *轻量级进程* 或 *任务*）的底层原语
—— 多个控制线程共享全局数据空间。为了处理同步问题，也提供了简单的锁机
制（也称为 *互斥锁* 或 *二进制信号*）。"threading" 模块基于该模块提供
了更易用的高级多线程 API。

The module is optional.  It is supported on Windows, Linux, SGI IRIX,
Solaris 2.x, as well as on systems that have a POSIX thread (a.k.a.
"pthread") implementation.  For systems lacking the "_thread" module,
the "_dummy_thread" module is available. It duplicates this module's
interface and can be used as a drop-in replacement.

It defines the following constants and functions:

exception _thread.error

   发生线程相关错误时抛出。

   在 3.3 版更改: 现在是内建异常 "RuntimeError" 的别名。

_thread.LockType

   锁对象的类型。

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

   启动一个线程，并返回其标识符。线程会用 *args* 作为参数（必须是元组
   ）执行 *function* 函数。可选的 *kwargs* 参数使用字典来指定有名参数
   。当函数返回时，线程会静默退出，当函数由于未处理的异常而中止时，会
   打印一条堆栈追踪信息，然后该线程会退出（但其他线程还是会继续运行）
   。

_thread.interrupt_main()

   在主线程中抛出 "KeyboardInterrupt" 异常。子线程可以使用这个函数来中
   断主线程。

_thread.exit()

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

_thread.allocate_lock()

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

_thread.get_ident()

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

_thread.stack_size([size])

   Return the thread stack size used when creating new threads.  The
   optional *size* argument specifies the stack size to be used for
   subsequently created threads, and must be 0 (use platform or
   configured default) or a positive integer value of at least 32,768
   (32 KiB). If *size* is not specified, 0 is used.  If changing the
   thread stack size is unsupported, a "RuntimeError" is raised.  If
   the specified stack size is invalid, a "ValueError" is raised and
   the stack size is unmodified.  32 KiB is currently the minimum
   supported stack size value to guarantee sufficient stack space for
   the interpreter itself.  Note that some platforms may have
   particular restrictions on values for the stack size, such as
   requiring a minimum stack size > 32 KiB or requiring allocation in
   multiples of the system memory page size - platform documentation
   should be referred to for more information (4 KiB pages are common;
   using multiples of 4096 for the stack size is the suggested
   approach in the absence of more specific information).
   Availability: Windows, systems with POSIX threads.

_thread.TIMEOUT_MAX

   "Lock.acquire()" 方法中 *timeout* 参数允许的最大值。传入超过这个值
   的 timeout 会抛出 "OverflowError" 异常。

   3.2 新版功能.

锁对象有以下方法：

lock.acquire(waitflag=1, timeout=-1)

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

   如果传入了整型参数 *waitflag*，具体的行为取决于传入的值：如果是 0
   的话，只会在能够立刻获取到锁时才获取，不会等待，如果是非零的话，会
   像之前提到的一样，无条件获取锁。

   如果传入正浮点数参数 *timeout*，相当于指定了返回之前等待得最大秒数
   。如果传入负的 *timeout*，相当于无限期等待。如果 *waitflag* 是 0 的
   话，不能指定 *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 is locked while this executes")

**注意事项：**

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

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

* 不可能中断锁的 "acquire()" 方法 —— "KeyboardInterrupt" 一场会在锁
  获 取到之后发生。

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

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