2016-07-08 12 views
1

Dies ist ein Beispielprogramm, das ich, dass gefunden ermöglicht es Ihnen, eine Schleifenaktion zu wechseln:Wie funktioniert die asynchrone Ausführung von 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 

Jetzt können wir sehen, dass einige Timeout-Art-of Anruf gibt es, die die Endlos-Schleife beginnt. Die Endlosschleife ist eindeutig synchron, es gibt keine Callbacks oder synchronisierte Blöcke oder so etwas.

Drücken Sie immer noch F12 scheint die Schleife ordnungsgemäß zu stoppen, auch wenn es ausgeführt wird.

Kann mir jemand erklären, wie Threads in autohotkey ausgeführt werden? Wie verarbeitet es mehrere Code-Blöcke ohne Rennbedingungen? Spielt der Anruf SetTimer eine Rolle dabei?

+1

nicht sicher, warum Sie fragen, ohne auf die Dokumentation der Suche: [ausführlich Einfädeln] (https://autohotkey.com/docs/misc/Threads.htm) , [SetTimer] (https://autohotkey.com/docs/commands/SetTimer.htm) negatives Timeout. – wOxxOm

+0

@wOxxOm Ich benutzte Google. Ich werde nicht Seite für Seite durch die Dokumente gehen - dafür habe ich keine Zeit und es ist nichts falsch daran, eine Frage zu stellen, auch wenn die Antwort woanders ist. Lesen Sie die Hilfe, wenn Sie sich nicht sicher sind. –

+0

Es dauert weniger als 1 Minute, um die Dokumentation zu öffnen und nach 'thread' zu suchen und eine weitere Minute für' SetTimer'. Das Posten der Frage hat mehr Zeit in Anspruch genommen. Darum habe ich mich gefragt. – wOxxOm

Antwort

3

TLDR: Threads können sich gegenseitig unterbrechen.

Werfen Sie einen Blick auf die AHK docs on Threads:

Obwohl AutoHotkey eigentlich nicht mehrere Threads verwenden, ist es simuliert einen Teil dieser Verhalten: Wenn ein zweiter Thread gestartet wird - so wie durch Drücken ein weiterer Hotkey, während der vorherige noch läuft - der aktuelle Thread wird unterbrochen (vorübergehend angehalten), damit der neue Thread aktuell werden kann. Wenn ein dritter Thread gestartet wird, während der zweite Thread noch ausgeführt wird, befinden sich sowohl der zweite als auch der erste Thread in einem Ruhezustand und so weiter.

New Thread vs. aktuelle Thread

Also in Ihrem Beispiel, wenn F12 gedrückt und toggle ist false, wird es das loop Unterprogramm läuft sofort und nur einmal (Periode -1). Das Unterprogramm wird wiederholt, bis toggle wieder false wird.
Hier kommt der Trick: Wenn Sie F12 erneut drücken, wird ein anderer Thread ausgeführt werden, und neue Themen zu den aktuellen Thread standardmäßig unterbrechen. Der neue Thread wird also die Schleife anhalten, toggle auf false setzen und dann elegant beenden, da die Hotkey-Subroutine nichts mehr zu tun hat. Nachdem die Hotkey-Subroutine beendet ist, wird der vorherige Thread (der unser loop-Timer ist) wieder zum Leben erweckt. Seit toggle ist jetzt false, wird es aus der Schleife ausbrechen und auch beenden ... und so ist der Kreis abgeschlossen. Beachten Sie, dass loop befohlen wurde, nur einmal zu laufen, also keine weitere Wiederholung dort.

Thema Prioritäten

Neue Themen können nur den aktuellen Thread unterbrechen, wenn ihre priority mindestens gleich dem aktuellen Threads Priorität. Standardmäßig hat jeder Thread die Priorität 0, und es spielt keine Rolle, ob es sich um einen Hotkey-Thread, eine zeitgesteuerte Subroutine oder eine andere Art von Thread handelt. Natürlich gibt es eine Ausnahme ...

Mit Sleep

Die AHK docs on Sleep sagen:

Während des Schlafes können neue Threads per Hotkey, benutzerdefinierte Menü Element gestartet werden, oder Timer.

Wenn ein Thread schläft, es wird im Grunde unterbrochen und entlastet alle CPU-Zeit für einen anderen Thread (nur für die Zeit, die es tatsächlich schläft). Das heißt, sogar Threads mit einer niedrigeren Priorität können ausgeführt werden, während der aktuelle Thread inaktiv ist. In Ihrem Beispiel gibt es eine wesentliche Sleep von 700 ms. Natürlich würde Ihr Skript auch ohne den Schlaf funktionieren und toggle wäre immer noch toggleable. Aber selbst wenn loop mit einer höheren Priorität aufgerufen worden wäre, wäre der Hokey trotzdem in der Lage zu laufen, während loop schläft (was praktisch die meiste Zeit ist).

Der Beispielcode stinkt

Das Codebeispiel Sie auf dem Laufenden arbeiten kann, aber IMO, ist verwirrend und geradezu schlechte Codierung. Der Hauptzweck von Timern ist es, periodisch zu laufen, aber hier haben wir eine Schleife innerhalb eines Timers, die den ganzen Zweck von Timern widersetzt. Wenn wir zulassen, dass ein Hotkey mehr als ein Thread zu erzeugen, könnten wir auch diese absurde verwenden aber die Arbeit Stück Code:

; Bad example! 
#MaxThreadsPerHotkey 2 
toggle := false 

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

Verwenden Timer für das, was sie gemeint sind

Hier ist zu tun, wie ich implementieren würde eine Toggle-Funktion, die Klicks alle 700ms verließ:

toggle := false 

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

DoLeftClick: 
    Click 
return 
1

Betrachten Sie dies nicht als eine vollständige Antwort.
Ich möchte nur hinzufügen, dass seit Version 1.1.20 fast immer Funktionen anstelle von Labels verwendet werden sollten. Dies vermeidet viele potentielle Konflikte (Labels werden im globalen Bereich ausgeführt).
So bevorzugt würden Sie es wie folgt tun:

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

DoLeftClick() { 
    Click 
} 
Verwandte Themen