Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Threadunterbrechung - nicht mit suspend (https://www.delphipraxis.net/185001-threadunterbrechung-nicht-mit-suspend.html)

Delphi-Laie 6. Mai 2015 20:11

Threadunterbrechung - nicht mit suspend
 
Hallo Delphifreunde!

Bekanntlich entscheidet Windows nach eigenem Gutdünken, wann und an welcher Stelle es Threads unterbricht und wann später an derselben Stelle (also dem nachfolgenden Befehl des letzten vor der Unterbrechung abgearbeiteten Befehls) fortsetzt.

Gibt es eine Möglichkeit, Windows an einer bestimmten Stelle zur Unterbrechung eines Threads (des eigenen Threads) aufzufordern (API-Befehl)?

Davon unbeschadet, kann und wird Windows diesen Thread natürlich auch an anderen Stellen unterbrechen, das soll und kann gar nicht verhindert werden.

Ich meine jetzt nicht das Befehlspaar suspend - resume, denn das erfordert ein separates Wiederaufnehmen des Thread von anderer Stelle (also aus einem anderen Thread), wenn ich das richtig verstanden habe. Windows kann und soll den Thread, der an definierter Stelle um seine Unterbrechung bat, eigenverantwortlich später wieder aktivieren.

Vielen Dank und Gruß

Delphi-Laie

Sir Rufo 6. Mai 2015 20:14

AW: Threadunterbrechung - nicht mit suspend
 
Das macht Delphi-Referenz durchsuchenTThread.Yield

Delphi-Laie 6. Mai 2015 20:18

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Sir Rufo (Beitrag 1300515)
Das macht Delphi-Referenz durchsuchenTThread.Yield

Danke!

Das erinnert mich an die jüngste Diskussion mit dem sleep(0) nach LeaveCriticalSection. Mit sleep(0) experimentierte ich an diesen Stellen (die kein Ende kritischer Abschnitte sind) auch schon, allerdings nicht mit zufriedenstellendem Ergebnis.

Muß ich mal herausfinden, ab welcher Delphiversion das Yield bereitgestellt wird und wie das ggf. in niedrigere Delphiversionen eingearbeitet werden kann. Hoffentlich funktionerte es damit besser.

Nochmals besten Dank!

Luckie 6. Mai 2015 20:27

AW: Threadunterbrechung - nicht mit suspend
 
Und warum willst du, dass der Thread an einer bestimmten Stelle unterbrochen wird? Mir erschließt sich nicht so ganz der Sinn dabei.

Delphi-Laie 6. Mai 2015 20:37

AW: Threadunterbrechung - nicht mit suspend
 
So, Yield hat intern auch nur ein sleep(x). Das Ergebnis ist mithin leider das gleiche wie mit sleep(0).

Zitat:

Zitat von Luckie (Beitrag 1300518)
Und warum willst du, dass der Thread an einer bestimmten Stelle unterbrochen wird? Mir erschließt sich nicht so ganz der Sinn dabei.

Luckie, das kannst Du gern wissen: Besorg Dir eines meiner aktuellen Sortierkinos und lasse den Algorithmus "Quicksort parallel (Multithreading)" auf zwei verschiedenen Windows mit Mehrkernprozessor ablaufen, eines bis XP, eines danach (meine Experimentierfelder sind einmal XP und dann noch ein Windows 7, auf 8.1 könnte ich es auch mal testen). Um besser zu sehen, worauf es mir ankommt, solltest Du die Darstellung ausbremsen.

Während auf XP die zeitliche Parallelität gut zu erkennen ist (gleichzeitige Partionierung der Sortierteilmengen), ist es auf Windows 7 anders: Da wird immer nur eine Teilmenge partitioniert, und das, obwohl mehrere bis etliche Threads gleichzeitig am Laufen sind (eigentlich). Das ist im Vergleich zu vorher unschön, schlichtweg ein Rückschritt. Irgendetwas ist auf Windows 7 (vermutlich ab Vista) in der Threadablaufsteuerung anders. Nun dachte und hoffte ich, daß man mit "provozierten" Threadunterbrechungen Windows (7) zu mehr Gleichzeitigkeit, die man optimalerweise sogar sehen könnte, bewegen könnte, aber leider Fehlanzeige. Muß es also erstmal so bleiben, wie es ist.

Daniel 6. Mai 2015 20:55

AW: Threadunterbrechung - nicht mit suspend
 
Wie extrem ist denn das Verhalten Deiner Anwendung denn unter Windows 7?
Hast Du nur "weniger" Parallelität oder laufen die Threads mehr oder weniger seriell ab?

Ich frage, weil ich mit dem klassischen Thread von Delphi (XE4 aufwärts) unter aktuellen Windows-Versionen stets das gewünschte parallele Verhalten erziele.

Delphi-Laie 6. Mai 2015 21:05

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Daniel (Beitrag 1300527)
Wie extrem ist denn das Verhalten Deiner Anwendung denn unter Windows 7?
Hast Du nur "weniger" Parallelität oder laufen die Threads mehr oder weniger seriell ab?

Ich frage, weil ich mit dem klassischen Thread von Delphi (XE4 aufwärts) unter aktuellen Windows-Versionen stets das gewünschte parallele Verhalten erziele.

Beim Multithreading-Quicksort war ich sogar schon mit dem Verhalten des Delphi-2-Compilates zufrieden, beim Multithreading-Mergesort benötigte ich Compilate ab Delphi 5, damit es auch auf XP ordnungsgemäß läuft.

Daniel, Du kannst es gern selbst ausprobieren, aber natürlich antworte ich auch: Auf Windows 7 ist es "extrem", denn da läuft - sichtbar - gar nichts mehr gleichzeitig, sondern nur noch sequentiell ab. Wie gesagt, auf XP war ich mit diesem Algorithmus rundum zufrieden, er lief genau so, wie ich es mir vorstellte. Wurde demnach wieder irgendetwas an Windows "rumgemacht"...

Delphi-Laie 6. Mai 2015 21:15

AW: Threadunterbrechung - nicht mit suspend
 
Habe es soeben ausprobiert: Unter Windows XP ist die gleichzeitige Partitionierung der Teilmengen im parallelen Quicksort sogar auf Einkernprozessoren prinzipiell zu erkennen. Ist zwar ziemlich hakelig, ruckelig, langsam, schlichtweg eine Qual für Windows, aber es funktioniert.

Daniel 6. Mai 2015 21:34

AW: Threadunterbrechung - nicht mit suspend
 
Ich habe Dein Projekt mal eben mit XE8 übersetzt - und ja, da wird sehr gemütlich sortiert. Schön ein Segment nach dem anderen.
Ich habe allerdings Deine globale CriticalSection im Verdacht und wenn ich das richtig sehe, wartest Du zudem blockierend (pollend) auf die Threads (die Zeilen mit repeat-until). Einen Aufruf von "WaitForMultipleObjects()" beispielsweise suche ich vergebens.

Kurzum: Ich bin mir nicht sicher, ob das Problem wirklich an Windows liegt.

Delphi-Laie 6. Mai 2015 21:40

AW: Threadunterbrechung - nicht mit suspend
 
Danke für Deine Mühe und die helfenden Hinweise, Daniel! Damit werde ich mich beschäftigen.

Ich programmiere als Hobbyprogrammierer bei den meisten Sachen, so auch hier, ständig am Limit, durch Lesen und Lernen, Versuch und Irrtum, wie viele eben. Was meinst Du, wie froh ich war, es soweit hinbekommen zu haben?!

Ergänzung: Das Polling gefällt mir auch nicht, aber mit Messages kann es m.E. nicht funktionieren. Alles schon ausprobiert, gescheitert, durchdacht und verinnerlicht.

Daniel 6. Mai 2015 21:52

AW: Threadunterbrechung - nicht mit suspend
 
Ja, das ist ein Knackpunkt, ging mir nicht anders - aber auch ein Durchbruch, wenn man es verinnerlicht hat.

Jeder Thread hat ein Handle. Die Idee ist es jetzt, die Threads zu starten und sich die Handles in einem Array zu merken. Dieses Array reicht man dann an eine API-Funktion wie "WaitForMultipleObjects()", die wartet, bis alle Threads fertig sind. Das Warten selbst ist zwar blockierend, verbraucht aber (so gut wie) keine CPU-Zyklen. Nach diesem Schema ist sichergestellt, dass alle Threads frei arbeiten können - im Rahmen dessen, was das Betriebssystem und der Prozessor eben hergeben. In diesem Fall dürfen sich die Threads allerdings nicht selbst freigeben, da Windows sonst keine Chance hat, deren Status abzufragen.

DP, EE und DT haben einige Einträge und Beispiele zu "WaitForMultipleObjects()". Ich empfand deren Lektüre als sehr erhellend.

Delphi-Laie 6. Mai 2015 21:55

AW: Threadunterbrechung - nicht mit suspend
 
Nochmals besten Dank!

Luckie 7. Mai 2015 00:04

AW: Threadunterbrechung - nicht mit suspend
 
ich werde immer misstrauisch, wenn man so anfängt zu tricksen um etwas zu erreichen. Dann macht man meist was verkehrt.

Delphi-Laie 7. Mai 2015 07:32

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Luckie (Beitrag 1300559)
ich werde immer misstrauisch, wenn man so anfängt zu tricksen um etwas zu erreichen. Dann macht man meist was verkehrt.

Was meinst Du mit "tricksen"? Meine Idee, Threadunterbrechungen bewußt auszulösen?

Luckie 7. Mai 2015 07:39

AW: Threadunterbrechung - nicht mit suspend
 
In diesem Fall ja.

Delphi-Laie 7. Mai 2015 14:36

AW: Threadunterbrechung - nicht mit suspend
 
Hallo Daniel, ich möchte Dich als Administrator über Gebühr beanspruchen, aber dennoch noch etwas einwenden.

Zitat:

Zitat von Daniel (Beitrag 1300539)
Dieses Array reicht man dann an eine API-Funktion wie "WaitForMultipleObjects()", die wartet, bis alle Threads fertig sind.

Das spielt bei diesem Algorithmus m.E. nicht die entscheidende Rolle. Jede (Teil-)Menge wird in eine große und kleine Teilmenge partitioniert und der Algorithmus auf beide mit je einem Extrathrad separat losgelassen. Da die beiden Teilmengen nichts mehr miteinander zu tun haben, dürfen auch die beiden Threads völlig unabhängig voneinander ihr Eigenleben entwickeln, den "Vaterthread" interessiert nur noch, ob bzw. daß die gestartet wurden. Vermutlich bist Du studierter Informatiker und weißt über die prinzipielle Funktionsweise dieses Sortieralgorithmus' bestens bescheid. Vor dem Problem, auf das Ende von (jeweils 2) Threads zu warten, um darauf zu reagieren, stand ich hingegen beim parallelen Mergesort, dort bekam ich es auf meine "Bastelweise" gelöst, unter allen mir zur Verfügung stehenden Windowsversionen.

Zitat:

Zitat von Daniel (Beitrag 1300539)
Das Warten selbst ist zwar blockierend, verbraucht aber (so gut wie) keine CPU-Zyklen.

Gut, mein Polling blockiert auch, aber nur solang, bis der (jeweilige) "Tochterthread" gestartet ist. Das wartet keinesfalls, bis dessen Partitionierung oder gar dessen gesamter Code abgearbeitet ist.

Zitat:

Zitat von Daniel (Beitrag 1300539)
Nach diesem Schema ist sichergestellt, dass alle Threads frei arbeiten können - im Rahmen dessen, was das Betriebssystem und der Prozessor eben hergeben.

Das ist bei meiner Lösung m.E. auch gegeben. Ich habe es genauer analysiert: (Jeweils) beide "Tochterthreads" starten (immer erst der linke, dann der rechte), was ich daran erkennen kann, daß es wie das Hornberger Schießen ausgeht, welchen Thread Windows daraufhin abarbeitet (also wiederum partitioniert): Mal ist es der linke, mal der rechte, aber eben immer nur einer zu jedem beliebigen Zeitpunkt. Und das trifft auf alle Threads zu: Windows (7) scheint immer nur einen Thread zu jedem beliebigen Zeitpunkt zur Abarbeitung freizugeben. Das ist das, was ich zuvor schrieb, daß etwas an der Threadablaufsteuerung gegenüber XP verändert worden sein muß. Schade, mir ist kein Taskmanager bekannt, der die Prozessorauslastung threadweise ermittelt bzw. anzeigt, aber in einem solchen müßte erkennbar sein, daß hierbei immer nur ein Thread just am Werkeln ist.

Vielleicht habe ich auch ein grundsätzliches Verständnisproblem und erwarte auch nicht, daß Du noch mehr Zeit in diese Diskussion investierst.

WaitForMultipleObjects werde ich natürlich weiterhin studieren.

Daniel 7. Mai 2015 15:15

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1300648)
[...] ich möchte Dich als Administrator über Gebühr beanspruchen [...]

;-)
Ich bin ab morgen für eine Woche im Urlaub. Von daher kann ich aktuell nicht nennenswert in das Thema einsteigen.
Ich müsste jetzt, um sinnvoll antworten zu können, tiefer in Deine Implementation gehen, um konkrete Aspekte ansprechen zu können. Das schaffe ich aktuell zeitlich leider nicht.

Delphi-Laie 7. Mai 2015 19:29

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1300648)
Hallo Daniel, ich möchte Dich als Administrator über Gebühr beanspruchen

Volltreffer, ich meinte natürlich nicht beanspruchen - Entschuldigung! Schönen Urlaub!

Delphi-Laie 7. Mai 2015 19:52

AW: Threadunterbrechung - nicht mit suspend
 
So, Daniel, Problem (anscheinend) gelöst: Ich habe es mit den CriticalSections wohl doch etwas übertrieben: So umhüllte ich auch synchronize damit. Warum, weiß ich selbst nicht mehr genau, ich probierte eben aus, wie meistens: Nach "Umhüllung" nahezu des gesamten Threadcodes ver- und zerkleinerte ("ziselierte") ich die kritischen Abschnitte soweit, wie es noch stabil blieb, um eine möglichst hohe Gleichzeitigkeit zu ermöglichen - und ja, ich schaute mir dabei natürlich auch an, daß Variablen nicht gleichzeitig lesenden und schreibenden Zugriff durch verschiedene Threads haben könnten, also ganz ohne Verständnis war ich dabei nicht zugange. Synchronize selbst ist aber eine Prozedur, die nach meinem Verständnis exklusiven Zugriff (auf die VCL) benötigt und damit per se als kritisch geschützt sein muß. Vielleicht lief es ohne diese "kritische Umhüllung" nicht stabil genug, jetzt bin ich aber ohne zufrieden.

Es funktioniert jedenfalls jetzt auch unter Windows 7 besser, also spürbar zeitparalleler, und das war mein eigentliches Ziel.

Besten Dank noch einmal an alle, die sich so rührend meiner annahmen!

Ergänzung: Beim parallelen Mergesort komme ich ohne diese kritische Umhüllung des synchronizes jedenfalls leider nicht aus, ist schon merkwürdig.

Ergänzung 2: Man sieht aber sehr schön, daß auch hier nur eine "handverlesene, elitäre Auswahl" an Threads aktiv ist - es werkeln jedenfalls nicht so viele optisch umher, wie m.E. möglich sind.

Luckie 7. Mai 2015 20:57

AW: Threadunterbrechung - nicht mit suspend
 
Da hatte ich ja das richtige Gefühl, dass es nicht an Windows liegt.

Delphi-Laie 10. Mai 2015 11:49

AW: Threadunterbrechung - nicht mit suspend
 
Zitat:

Zitat von Luckie (Beitrag 1300701)
Da hatte ich ja das richtige Gefühl, dass es nicht an Windows liegt.

Ganz so eindeutig ist die Schuldfrage hier aus meiner Sicht nicht, Luckie. Immerhin wurde eindeutig etwas an Windows verändert. Analogum: Die neuen Styles übernehmen ab Windows Vista (?) das Neuzeichnen meistens, man kann demnach ein beschäftigtes Single-Thread-Programm nicht mehr wie früher "weißwischen". Wenn ein Programmierer für Windows bis XP sich darauf einstellt und später dieses Neuzeichnen für den Programmablauf wichtig ist, es aber fehlt, ist er dann "schuld"? Programmierer sind einen erheblichen Teil ihrer Arbeitszeit damit beschäftigt, ihre Programme an die neusten Eigenheiten des jeweiligen Betriebsprogrammes anzupassen, ja, sich die nötigen Informationen dazu erstmal zu beschaffen, aber wem sage ich das?

Daß in dem einen Falle das Einbetten einer Synchronize-Prozedur (die m.E. per se "kritisch geschützt" ist) nötig ist, nämlich beim Multithreading-Mergesort, in dem anderen Falle, beim Multithreading-Quicksort hingegen in neueren Windows (wohl ab Windows 7) die Gleichzeitigkeit bis zur völligen Serialität (immer nur ein Thread anscheinend aktiv) abmindert, darauf muß man erstmal kommen. Ich kam nicht gedanklich, sondern letztlich nur über Experimente darauf.

Jedenfalls funktioniert es jetzt so, wie ich es beabsichtigte, auch in modernen Windows. Daniels Hinweis mit der CriticalSection führte mich auf die entscheidende Fährte. Vielen Dank Euch allen!


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:04 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz