Task.WaitAll () ne fonctionne pas comme prévu

J’essaie de comprendre comment travailler avec la classe de tâches. Dans le passé, j’ai toujours utilisé la classe Thread standard, mais j’essaie de saisir toute la programmation asynchrone …

Par exemple, j’ai créé une application Winforms principale qui contient tout le code. Le code pertinent pour mon problème est:

//Relevant delegates public delegate void MethodAction(int num); public delegate void MethodConversion(); public delegate void OnCompletionAction(ssortingng completiontext); //Button user presses private void button4_Click(object sender, EventArgs e) { richTextBox1.Clear(); sw.Reset(); sw.Start(); Sync.RunAsync3(calcSim); } //The method that simulates a calculation by adding a sleep //the input param threadlength is just to allow threads to take longer than others //since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control private void calcSim(int threadlength) { ssortingng threadname = Thread.CurrentThread.Name; for (int i = 0; i  { richTextBox1.AppendText(ssortingng.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToSsortingng())); })); } } //Class that contains the different processing methods public static class Sync { public static event OnCompletionAction OnProcCompletion; public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } Task.WaitAll(t); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } } 

Le problème réside dans Task.WaitAll (t) … Pour une raison que je ne comprends pas, cela bloque complètement la ligne et ne répond plus. Si j’omets cette ligne, le formulaire est mis à jour en temps réel et l’exécution prend environ 3 secondes.

Ma question est la suivante: pourquoi Task.WaitAll () ne bloque-t-il pas le thread d’interface utilisateur pendant 3 secondes avant de le relâcher et de permettre l’exécution du rest du code?

Je sais que cela devrait bloquer l’interface utilisateur pendant un certain temps (jusqu’à ce que tous les threads soient calculés), mais cela bloque l’application complète à l’infini. Il semble attendre pour toujours?

MODIFIER

On m’a suggéré d’utiliser WhenAll au lieu de WaitAll. J’ai réécrit RunAsync3 comme suit:

 public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } //Task.WaitAll(t); -> deadlock Task.WaitAll(new Task [] { Task.WhenAll(t) }); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } 

Mais cela est toujours dans l’impasse …? J’utilise peut-être le WhenAll incorrectement?

EDIT 2

Parce que tout le monde affirmant que je bloquais le fil de l’interface utilisateur avait raison, j’ai décidé d’essayer cela d’une autre manière: en exécutant un nouveau fil en tant que fil d’appel dans le fil de l’interface utilisateur (pour que le blocage se produise maintenant sur mon fil au lieu du fil de l’interface utilisateur). Cela fonctionne, mais ce n’est évidemment pas la meilleure façon de le faire!

 private void button4_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(() => { richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear())); sw.Reset(); sw.Start(); Sync.RunAsync3(calcSim); })); t.Start(); } public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } Task.WaitAll(t); //Task.WaitAll(new Task [] { Task.WhenAll(t) }); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } 

Vous créez une impasse.

Le thread d’interface utilisateur attend que 4 tâches soient terminées.

D’autre part, ces 4 tâches, exécutant calcSim tentent d’invoquer du code sur le thread d’interface utilisateur -> Deadlock.

Vous devriez plutôt utiliser Task.WhenAll() . Cette méthode renverra une nouvelle tâche qui sera marquée comme terminée lorsque toutes vos tâches pour sont terminées. Si vous attendez cette tâche, votre thread d’interface utilisateur sera libéré, ce calcSim permettra à calcSim d’appeler du code sur le thread d’interface utilisateur, évitant ainsi un blocage.

Mettre à jour

Vous l’utilisez mal. Vous utilisez toujours WaitAll , qui est un appel bloquant. Vous devriez le remplacer par WhenAll .

 await Task.WhenAll(t); 

De la documentation :

Crée une tâche qui se terminera lorsque toutes les tâches fournies seront terminées.

En appelant await sur le résultat, votre thread d’interface utilisateur sera libre – jusqu’à ce que les 4 tâches soient terminées. Lorsque cela se produit, votre méthode RunAsync3 reprendra.

Task.WaitAll bloque et attend que toute tâche soit terminée et que vous l’appelez sur le thread d’interface utilisateur.

Toutes vos tâches tentent d’appeler richTextBox1.Invoke (dans le thread d’interface utilisateur), mais votre thread d’interface utilisateur est bloqué dans Task.WaitAll . Impasse.

Parce qu’il attend que vos discussions se terminent. Ils courent exactement 3 secondes 300X10