这是我发现的示例程序,它允许您切换一些循环操作:
SetTimer
现在我们可以看到有一些超时类型的调用会启动无限循环。无限循环显然是同步的,没有回调或同步块或任何东西。
仍然,按 F12 似乎可以正常停止循环,即使它正在运行。
有人可以向我解释如何在autohotkey中执行线程吗?如何在没有竞争条件的情况下处理多个代码块? {{1}}调用是否在此中扮演任何角色?
答案 0 :(得分:5)
TLDR:线程可以互相中断。
虽然AutoHotkey实际上并不使用多个线程,但它 模拟一些行为:如果第二个线程启动 - 这样 通过在前一个仍在运行时按另一个热键 - 当前线程将被中断(暂时停止)以允许 新线程成为当前的。如果第三个线程启动的话 第二个仍在运行,第二个和第一个将在一个 休眠状态,等等。
因此,在您的示例中,如果按下F12
且toggle
为false
,则会立即运行loop
子例程且仅运行一次 (-1
期)。子程序将循环,直到toggle
再次成为false
诀窍就是:如果再次按F12
,则运行另一个线程,新线程默认中断当前线程。所以新线程将暂停循环,将toggle
设置为false
然后优雅地完成,因为热键子例程没有任何事情要做。热键子例程完成后,前一个线程(我们的loop
计时器)恢复生机。由于toggle
现在是false
,它会突破循环并完成...所以圈子就完成了。请注意loop
被命令只运行一次,所以不再重复。
如果priority的AHK docs on Sleep至少等于当前线程的优先级,则新线程只能中断当前线程。默认情况下,每个线程的优先级都为0
,如果它是热键线程,定时子例程或任何其他类型的线程,则无关紧要。当然,有一个例外...
Sleep
在睡觉时,可以通过热键自定义菜单启动新线程 项目或计时器。
如果线程处于休眠状态,它基本上会被中断,并为任何其他线程释放所有 CPU时间(仅在它实际休眠的时间)。也就是说,即使具有较低优先级的线程也可以在当前线程休眠时运行。在您的示例中,有大约Sleep
700毫秒。当然,即使没有睡眠,您的脚本也可以正常工作,toggle
仍然可以切换。但是即使loop
被调用的优先级更高,在loop
正在睡觉时(实际上大部分时间都是如此),仍然能够运行。
您发布的代码示例可能有效,但IMO,令人困惑且完全不好编码。定时器的主要目的是定期运行,但这里我们在定时器中有一个循环,它违背了定时器的整个目的。 如果我们允许Hotkey产生多个线程,我们甚至可以使用这个荒谬但有效的代码:
; Bad example!
#MaxThreadsPerHotkey 2
toggle := false
F12::
toggle := !toggle
while(toggle) {
SoundBeep
Sleep, 500 ; Would even work without the Sleep
}
return
以下是我将如何实现每700毫秒点击一次的切换功能:
toggle := false
F12::
toggle := !toggle
if(toggle) {
SetTimer, DoLeftClick, Off
} else {
SetTimer, DoLeftClick, 700
}
return
DoLeftClick:
Click
return
答案 1 :(得分:2)
不要认为这是一个完整的答案 我想补充一点,因为v1.1.20你应该几乎总是使用函数而不是标签。这避免了许多潜在的冲突(标签在全球范围内执行) 所以你最好这样做:
F12::
__F12() {
Static toggle := False
toggle := !toggle
SetTimer, DoLeftClick, % toggle ? 700 : "Off"
}
DoLeftClick() {
Click
}