autohotkey的异步执行如何工作?

Tom*_*ica 3 asynchronous autohotkey

这是我发现的示例程序,它将允许您切换一些循环操作:

; This toggles the action
toggle:=false

F12::
; If true is assigned to toggle, loop starts
; It also can assign false even when loop is running
If (toggle := !toggle)
    SetTimer, loop, -1
return

loop:
; Endless loop? Actually not, the value of toggle can be changed by
; another "thread" even when this loop is running
while toggle
{
    Click
    Sleep, 700
}
return
Run Code Online (Sandbox Code Playgroud)

现在我们可以看到有一些超时调用开始了无限循环。无限循环显然是同步的,没有回调或同步的块或任何东西。

尽管如此,按F12一下似乎可以正确停止循环,即使循环正在运行也是如此。

有人可以向我解释如何在autohotkey中执行线程吗?如何在没有竞争条件的情况下处理多个代码块?是否SetTimer调用在其中发挥什么作用?

MCL*_*MCL 5

TLDR:线程可以互相中断。

看看Threads上的AHK文档

尽管AutoHotkey实际上并没有使用多个线程,但是它模拟了某些行为:如果启动了第二个线程-例如在前一个线程仍在运行时通过按下另一个热键-当前线程将被中断(暂时中止)到允许新线程成为当前线程。如果在第二个线程仍在运行时启动了第三个线程,则第二个线程和第一个线程都将处于休眠状态,依此类推。

新线程与当前线程

因此,在您的示例中,如果F12按和togglefalse,它将立即且仅运行一次loop子例程(周期为)。子例程将循环直到再次变为。 诀窍出在这里:如果再次按,将运行另一个线程,默认情况下,新线程会中断当前线程。因此,新线程将暂停循环,设置为,然后正常结束,因为热键子例程无事可做。热键子例程完成后,上一个线程(这是我们的计时器)恢复工作。从现在开始,它将跳出循环并结束...,因此圈是完整的。请注意-1togglefalse
F12togglefalselooptogglefalseloop 被命令只运行一次,所以在那里不再重复。

线程优先级

如果新线程的优先级至少等于当前线程的优先级,则它们只能中断当前线程。默认情况下,每个线程的优先级都为0,并且它是热键线程,定时子例程还是任何其他类型的线程都没有关系。当然,有一个例外...

使用 Sleep

对睡眠AHK文档说:

在睡眠期间,可以通过热键,自定义菜单项或计时器启动新线程。

如果一个线程正在休眠,则它基本上会被中断并为其他任何线程释放所有CPU时间(仅用于其实际休眠的时间)。也就是说,即使优先级较低的线程也可以在当前线程处于休眠状态时运行。在您的示例中,大约Sleep有700毫秒。当然,即使没有睡眠,您的脚本也可以工作并且toggle仍然可以切换。但是,即使loop被优先级较高地调用,该曲棍球仍可以在loop睡眠时运行(这实际上是大多数时间)。

示例代码很臭

您发布的代码示例可能有效,但IMO令人困惑,并且完全是错误的代码。计时器的主要目的是定期运行,但是这里我们在计时器中存在一个循环,这违背了计时器的全部用途。如果我们允许热键产生多个线程,我们甚至可以使用以下荒谬但有效的代码段:

; Bad example!
#MaxThreadsPerHotkey 2
toggle := false

F12::
    toggle := !toggle
    while(toggle) {
        SoundBeep
        Sleep, 500 ; Would even work without the Sleep
    }
return
Run Code Online (Sandbox Code Playgroud)

使用计时器来完成它们的工作

这是实现每700毫秒单击一次的切换功能的方法:

toggle := false

F12::
    toggle := !toggle
    if(toggle) {
        SetTimer, DoLeftClick, Off
    } else {
        SetTimer, DoLeftClick, 700
    }
return

DoLeftClick:
    Click
return
Run Code Online (Sandbox Code Playgroud)