Seite 2 von 2

Re: GUI- und WorkerThread

Verfasst: 21.07.2017, 14:43
von BeRsErKeR
Ich bin mir da auch nicht 100% sicher, wie die Event-Semantik ist. Tatsache ist jedenfalls, dass man non-volatile Membervariablen in völlig unabhängigen Events korrekt verwenden kann, ohne dass da was optimiert wird. In Hinblick auf Events habe ich in C# aber schon gruselige Sachen gesehen. Die Controls basieren ja mal auf den guten alten WinAPI-Controls und teilweise sind sie rein in .NET implementiert. Im CallStack von Events sieht man gerne mal ein Stück nativen Code dazwischen. Was da passiert ist nicht immer so ganz eindeutig. Ob da alles nur im UI-Thread läuft, weiß ich auch nicht so genau.

Eine sichere Alternative zu volatile wäre auch eine Property an Stelle einer Variablen. Das macht der BackgroundWorker übrigens auch mit CancellationPending. CancelAsync() setzt intern ein Flag und der Worker-Thread prüft es über die Property. Dadurch ist es dann auch thread-safe.

Re: GUI- und WorkerThread

Verfasst: 21.07.2017, 14:57
von joggel
Krishty hat geschrieben: Die Moral ist übrigens für joggel, so viele fertige Schnittstellen wie möglich zu nutzen, denn Multithreading selber machen ist – das sehen wir gerade – knifflig …
Jawohl...kam an^^
Aber das Thema finde ich trotzdem interessant...

Re: GUI- und WorkerThread

Verfasst: 21.07.2017, 15:04
von mrz
Krishty hat geschrieben:
mrz hat geschrieben:Hat mit CPU Caches zu tun.
Nein, mit dem Compiler. Die Sache läuft so ab:
  1. DoThisAllTheTime() muss optimiert werden.
  2. Es benutzt eine Variable shutdown.
  3. shutdown beginnt false und wird ausschließlich in MainForm_Closed() verändert.
  4. MainForm_Closed() wird in DoThisAllTheTime() niemals aufgerufen.
  5. Also wird shutdown niemals geändert.
  6. Also darf der Optimizer alle Vorkommen von shutdown durch die Konstante false ersetzen.
Resultat: Wenn der eine Thread dann shutdown = true setzt, passiert in dem anderen Thread nichts.

volatile teilt dem Compiler mit, dass sich shutdown eben doch ändern kann, auch wenn es nicht durch den aktuellen Thread geschrieben wird.

Die CPU-Caches spielen da erstmal keine Rolle; tatsächlich bewirkt volatile aber auch, dass der Compiler die Caches synchronisiert, bevor er aus shutdown liest. Auf x86 sind die Caches aber sowieso immer synchron* und da muss nichts gemacht werden.

* Außer bei SSE 2-Befehlen, die die Cache-Hierarchie umgehen; sowas benutzt der C#-Compiler aber nicht.
Nein weder der Compiler noch der Optimizer darf überall shutdown mit false ersetzen.
C# hat wie Java so ein Ding welches sich Reflection schimpft.
In Java darf das nur gemacht werden wenn die Variable "final" (=Immutable) ist.
In C# müsste es dafür "const" geben.
Zumindest in Java hat man btw sogar die Möglichkeit mit Reflection den final Modifier zu entfernen damit man dann auch final Variablen ändern kann.
Allerdings muss man damit rechnen dass ggf Änderungen an der Variable "niemand sieht" (weil schon ersetzt/optimiert wurde).
Die JVM tut teilweise "final" auch nicht komplett als Immutable betrachten (und somit nur bedingt optimiert werden kann),
dass kommt wegen dem Serializable Support.

Grundsätzlich hast Du aber natürlich Recht dass volatile vom Compiler ausgewertet wird und nur indirekt Einfluss auf die Caches hat.

Re: GUI- und WorkerThread

Verfasst: 21.07.2017, 15:56
von Krishty
Alles durch false zu ersetzen ist auch weit hergeholt, das muss ich zugeben. (Unter C++ schafft es nicht einmal Clang, unbenutzte Felder aus Klassen wegzuoptimieren.) Außerdem habe ich die Trennung von Compiler & JITter weggelassen, das ist auch nicht so pralle.

Die weitaus wahrscheinlichere Gefahr ist, dass die Variable in einem Register landet, und deshalb nur bei Betreten der Funktion einmal ausgewertet wird. (Sowas ist nur noch umständlicher zu erklären, weil deutlich mehr Faktoren in die Entscheidung hereinspielen.)

Wenn ich sowas lese wie hier auf StackOverflow, scheint das auch tatsächlich zu passieren (obwohl ich vor lauter Edits nicht mehr verstehe, ob der 2. Aufruf nun im Register landete oder ob’s das Inlining war).