# 线程

当前线程 的定义为最近事件调用的执行流; 例如包括热键, 计时器子程序, 自定义菜单项和 GUI 事件. 当前线程 可以在其自身子程序或该子程序调用的其他子程序中执行函数.

尽管 AutoHotkey 实际上并不支持多线程, 但它模拟了多线程的某些特性: 如果启动了第二个线程 -- 例如在前一个线程仍在执行时按下另一个热键 -- 那么 当前线程 会被中断(暂时停止) 以允许新线程变为 当前线程. 如果在第二个线程还在运行时又启动了第三个线程, 那么第二个和第一个线程都会进入休眠状态, 依此类推.

当 当前线程 结束时, 将恢复执行最近中断的线程, 依此类推, 直到所有线程最终结束. 当线程被恢复时, 它的设置例如 SendMode 和 SetKeyDelay 会自动恢复到中断前的状态; 换句话说, 中断不会给线程带来副作用(活动窗口可能发生的更改除外).

注意: KeyHistory 函数/菜单项会显示处于中断状态的线程数量, 而 ListHotkeys 函数/菜单项则显示拥有线程的热键.

一个脚本可以有多个同时发生的 MsgBox, InputBox, FileSelect 和 DirSelect 对话框. 这是在前一个线程已经显示对话框时, 通过启动一个新的线程(通过热键, 计时器子程序, 自定义菜单项, 等.) 来实现的.

默认情况下, 如果给定的热键或热字串子程序已经在运行, 则不能再次启动. 请使用 #MaxThreadsPerHotkey 来改变此特性.

相关: Thread 函数用于设置线程的优先级或中断性.

## 线程优先级

任何优先级低于 当前线程 的线程(热键, 计时子程序, 自定义菜单项, 等.), 不能中断当前线程. 在这种时候, 如计时器不会运行, 任何用户创建线程(如, 通过按下热键或 GUI 按钮) 的尝试都不会产生任何效果, 也不会被缓存起来. 由于这个原因, 通常在设计时最好让高优先级的线程快速结束, 或使用 Critical 而不将它们设置成高优先级.

默认的优先级为 0. 所有线程使用默认的优先级, 不过可以使用下列的其中一种方法来改变:

- 通过 SetTimer 给计时子程序指定优先级.
- 通过 Hotkey 函数给热键指定优先级.
- 在定义热字串时指定优先级, 或通过 #Hotstring 指令给热字串指定优先级.
- 通过 Menu.Add 方法给自定义菜单项指定优先级.
- 通过 Thread 函数给 当前线程 设置自己的优先级.

不论 当前线程 的优先级如何, OnExit 回调函数(如果有) 被调用时总是会运行.

## 线程可中断性

对于大多数类型的事件, 只有在当前线程 可中断 的情况下, 才允许启动新的线程. 一个线程可以因为一些原因而 不可中断, 包括:

- 线程已被标记为 critical. Critical 可能已经被线程本身或被自动执行线程调用.
- 线程运行时间不够长, 无法满足线程中断设置的成为可中断的条件, 如 Thread "Interrupt" 设置的.
- 脚本的一个菜单正在显示(如托盘图标菜单或菜单栏).
- Send(最常见的是由于 SetKeyDelay), WinActivate 或 Clipboard 操作正在执行延迟.
- OnExit 线程正在执行.
- 由于达到了 A_MaxHotkeysPerInterval 的限制, 或者由于激活键盘或鼠标钩子的问题(非常罕见), 正在显示一个警告对话框.

### 不可中断线程的特性

与高优先级线程不同, 线程不可中断时产生的事件不会被丢弃. 例如, 在当前线程不可中断时用户按下了热键热键就会被无限期地缓冲, 直到当前线程结束或变得可中断时, 热键才作为新的线程启动.

在紧急情况下, 任何线程都可能被中断. 紧急情况包括:

- 一个 OnExit 回调.
- 任何监视没有缓冲的消息的 OnMessage 函数.
- 任何由线程自身间接触发的回调(例如, 通过 SendMessage 或 DllCall).

要避免被这些事件中断, 可以临时禁用这些函数.

当显示 MsgBox 或其他对话框时, critical 会变得可中断. 但与 Thread Interrupt 不同的是, 在用户解除对话框后, 线程又变成了 critical(因此不可中断).

dftg