Seite 1 von 1

(gelöst)[C#] Warum funktioniert das?

Verfasst: 03.07.2016, 16:36
von Krishty
Ich muss gerade über folgenden Quelltext schauen, der Arbeit in einen separaten Thread auslagern soll:
  • var threadFunc = (SendOrPostCallback)delegate { ...... };

    var job = Dispatcher.BeginInvoke(DispatcherPriority.Background, threadFunc, null);

    job.Completed += ui_onCompletion;
Als Native-Entwickler sah das für mich sofort nach Race Condition aus:
  1. BeginInvoke() startet den Worker
  2. der Worker ist fertig, bevor der Haupt-Thread job.Completed += ui_onCompletion; aufruft
  3. ui_onCompletion() wird niemals aufgerufen und das Programm hängt
Ich wollte diese Race Condition provozieren, und habe es nicht geschafft: threadFunc() wird erst *nach* job.Completed += ui_onCompletion; aufgerufen; egal, was ich mache.

Nun wollte ich prüfen, ob das eine API-Garantie ist. Leider ist die Dokumentation von System.Windows.Threading.Dispatcher.BeginInvoke() und System.Windows.Threading.DispatcherOperation.Completed so gut wie wertlos.

Das Verhalten, das ich beobachte, lässt sich im Augenblick nur erklären durch
  1. Der Worker startet erst, nachdem job aufgeräumt wurde, was durch den Garbage Collector aber nicht deterministisch ist
  2. Der Worker wird in irgendeine Warteschlange eingereiht, die erst abgearbeitet wird, wenn der Haupt-Thread das nächste Mal seine Nachrichten verarbeitet, was aber irgendwie dem Zweck eines Thread Pools widerspricht
Kann mir jemand erklären, warum das funktioniert, und ob dieses Verhalten garantiert (der Code also in Ordnung) ist?

Re: [C#] Warum funktioniert das?

Verfasst: 03.07.2016, 16:56
von xq
Dispatcher ist kein Thread Pool sondern eine Möglichkeit, Funktionen im Haupt-Thread aufzurufen. BeginInvoke reiht die Nachricht ein, Invoke wartet auch noch auf die Completion.

Ansonsten kann der Job auch beim Hinzufügen des events darauf reagieren, wenn der Job schon completed ist und das Event dann sofort aufrufen.

Für "richtiges" Thread Pooling guck mal die Klassen Task, Thread und ThreadPool. Falls du in dem Fall den wirklich nen parallelen Thread verwenden willst, empfehle ich dir Task<T> mit await/yield

Re: [C#] Warum funktioniert das?

Verfasst: 03.07.2016, 17:02
von Krishty
Also ungefähr meine 2. Vermutung? Und als mein UI-Mann dachte, dass er die Arbeit in einen 2. Thread geschoben hätte, hat er sie in Wirklichkeit in die Idle-Zeit des Haupt-Threads geschoben?

Re: [C#] Warum funktioniert das?

Verfasst: 03.07.2016, 19:12
von xq
Richtig, genau das. Im Normalfall spawnt man einen Task<T> in der UI und gibt das ergebnis entweder mit await/async oder mit dem Dispatcher an den Main Thread zurück

Re: [C#] Warum funktioniert das?

Verfasst: 03.07.2016, 20:25
von Krishty
Danke vielmals! :)