2016-07-08 269 views
1

這是示例程序,我發現,讓你切換回路的一些動作: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 

現在我們可以看到,有一些超時實物-的呼叫啓動無限循環。無限循環顯然是同步的,沒有回調或同步塊或任何東西。

仍然,按F12似乎正常停止循環,即使它正在運行。

有人可以向我解釋在autohotkey中執行線程的方式嗎?它如何在沒有競爭條件的情況下處理多個代碼塊? SetTimer調用在此扮演什麼角色?

+1

不知道爲什麼你問不看的文檔:[詳細線程(https://autohotkey.com/docs/misc/Threads.htm) ,[SetTimer](https://autohotkey.com/docs/commands/SetTimer.htm)的否定超時。 – wOxxOm

+0

@wOxxOm我用谷歌。我不會逐頁瀏覽文檔 - 我沒有時間去閱讀,即使答案在其他地方,提問也沒有錯。如果您不確定,也許可以閱讀幫助中心。 –

+0

只需要不到1分鐘的時間打開文檔並搜索「線程」,另外1分鐘搜索「SetTimer」。發佈這個問題需要更多的時間。這就是我想知道的。 – wOxxOm

回答

3

TLDR:線程可能會相互中斷。

看一看的AHK docs on Threads

儘管AutoHotkey的實際上並沒有使用多線程,它 模擬一些行爲:如果第二個線程被啓動 - 例如 通過按壓另一個熱鍵,而以前仍在運行 - 當前線程將被中斷(暫時停止),以允許 新線程成爲當前。如果第三個線程在 的第二個仍在運行時啓動,則第二個和第一個將處於休眠狀態,依此類推。

新線程與當前線程

因此,在你的榜樣,如果按下F12togglefalse,它會立即運行loop子程序只有一次(的-1期)。該子程序將循環直到toggle再次變爲false
訣竅:如果再次按F12,則會運行另一個線程,並且默認情況下,新線程會中斷當前線程。因此,新線程將暫停循環,將toggle設置爲false,然後優雅地完成,因爲熱鍵子例程沒有什麼可做的。熱鍵子程序結束後,前一個線程(這是我們的loop定時器)將恢復生機。由於toggle現在是false,它將跳出循環並完成...所以圓是完整的。請注意,loop已被命令僅運行一次,因此不會再有重複。

線程優先級

新線程只能中斷當前線程,如果他們priority至少等於當前線程的優先級。默認情況下,每個線程的優先級爲0,無論它是熱鍵線程,定時子例程還是任何其他類型的線程都無關緊要。當然,有一個例外......

使用Sleep

AHK docs on Sleep說:

睡覺時,新的線程可以通過熱鍵啓動,自定義菜單項 或定時器。

如果一個線程處於休眠狀態,它基本上被中斷,並釋放所有CPU時間任何其他線程(僅適用於它實際上睡覺的時間)。也就是說,即使當前線程正在休眠時,優先級較低的線程也可以運行。在你的例子中,有一個700毫秒的大致Sleep。當然,即使沒有睡眠,你的腳本也可以工作,並且toggle仍然是可切換。但即使loop被調用的優先級較高,hokey仍然可以運行,而loop正在睡覺(實際上大部分時間都是這樣)。

的示例代碼好臭

你可以發佈工作,但海事組織,是混亂和徹底的壞的編碼代碼示例。定時器的主要目的是定期運行,但在這裏我們有一個定時器內的循環,這違背了定時器的全部目的。 如果我們允許一個熱鍵產卵多個線程,我們甚至可以利用這個荒謬的,但工作一段代碼:

; Bad example! 
#MaxThreadsPerHotkey 2 
toggle := false 

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

使用定時器爲他們的意思做

這是我將如何實現一個切換功能,每700ms左鍵點擊一次:

toggle := false 

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

DoLeftClick: 
    Click 
return 
1

不要認爲這是一個完整的答案。
我只想補充一點,自從v1.1.20開始,你應該幾乎總是使用函數而不是標籤。這避免了很多潛在的衝突(標籤在全局範圍內執行)。
所以最好你會做這樣的:

F12:: 
__F12() { 
    Static toggle := False 
    toggle := !toggle 
    SetTimer, DoLeftClick, % toggle ? 700 : "Off" 
} 

DoLeftClick() { 
    Click 
}