Thread Join () bewirkt, dass Task.RunSynchron nicht beendet wird

8

Der Aufruf von _thread.Join() bewirkt, dass die GetConsumingEnumerable -Schleife beim letzten Element hängen bleibt. Warum tritt dieses Verhalten auf?

%Vor%

Der Kontext für diesen Ansatz besteht darin, dass ich sicherstellen muss, dass alle Operationen auf einem Betriebssystem-Thread ausgeführt werden, wodurch ein Teil der Anwendung andere Anmeldeinformationen als der Haupt-Thread verwenden könnte.

    
VoightKampff 13.06.2015, 20:11
quelle

2 Antworten

5

async-await arbeitet mit Fortsetzungen. Um effizient zu sein und die Planung zu reduzieren, werden diese Fortsetzungen normalerweise auf demselben Thread ausgeführt, der die vorherige Aufgabe abgeschlossen hat.

Das bedeutet in Ihrem Fall, dass Ihr spezieller Thread nicht nur die Aufgaben ausführt, sondern auch alle Fortsetzungen nach diesen Aufgaben ausführt (die for Schleife selbst). Sie können dies durch Drucken der Thread-ID sehen:

%Vor%

Wenn die for -Schleife abgeschlossen ist und die SampleActor entfernt wurde, rufen Sie Thread.Join von demselben Thread auf, mit dem Sie sich verbinden möchten, damit Sie einen Deadlock erhalten. Ihre Situation läuft darauf hinaus:

%Vor%

In .Net 4.6 können Sie dies mit TaskCreationOptions.RunContinuationsAsynchronously lösen, aber in der aktuellen Version können Sie den Standard TaskScheduler :

angeben %Vor%     
i3arnon 13.06.2015, 21:01
quelle
4

Es könnte verlockend sein, eine einfache Überprüfung vorzunehmen, um zu sehen, ob der Thread, den Sie versuchen, Join ist Thread.CurrentThread , aber das wäre falsch.

Außerdem denke ich, dass der gesamte Ansatz - das Planen und Ausführen von Cold Task -Objekten mit einem benutzerdefinierten, nicht TPL-konformen Scheduler - falsch ist . Sie sollten einen TPL-freundlichen Taskplaner verwenden, ähnlich wie Stephen Toub StaTaskScheduler . Oder führe einen benutzerdefinierten SynchronizationContext für deinen Aktor-Serving-Thread aus (wie Toubs AsyncPump ) und verwenden Sie TaskScheduler.FromCurrentSynchronizationContext und Task.Factory.StartNew , um Aufgaben mit Ihrem benutzerdefinierten Scheduler zu planen (oder verwenden Sie Task.Start(TaskScheduler) , wenn Sie mit kalten Aufgaben fertig werden müssen).

Auf diese Weise haben Sie die vollständige Kontrolle darüber, wo Aufgaben und deren Fortsetzungen ausgeführt werden, sowie inlining .

    
Noseratio 13.06.2015 23:59
quelle