2017-10-21 81 views
4

J'ai une application de console C# dans laquelle je peux, entre autres, entrer via une connexion socket TCP. Comment passer au thread principal quand je reçois une entrée via la fonction de réception sur le socket?Modification du contexte de thread dans l'application console C#

donc similaire à quelque chose comme ça dans WPF:

public void TaskDispatcher() 
{ 
    if (DispatcherObjectForTaskDispatcher.Thread != System.Threading.Thread.CurrentThread) 
     DispatcherObjectForTaskDispatcher.Invoke(new TaskDispatcherDelegate(TaskDispatcher)); 
    else 
    { 
     // Do some thing in the UI thread 
    } 
} 
+2

Pas très clair. Une application Console n'a pas d'interface utilisateur et donc pas de «thread d'interface utilisateur». Il n'a également pas de SyncContext. Vous avez probablement juste besoin d'une configuration Producer/Consumer ou quelque chose. –

+0

Non bien sûr, mais pas un thread principal, le thread dans lequel le vide statique Main (string [] args) fonctionne et la fonction de réception a un thread différent. Celui avec le fil de l'interface utilisateur était juste un exemple. – uhwgmxorg

+0

Mais oui, le modèle de flux de données producteur-consommateur semble être le bon indice. – uhwgmxorg

Répondre

1

Il suffit d'utiliser un modèle Producer-Consumer comme dans l'exemple ci-dessous travail. Mettez en file d'attente les tâches provenant d'autres threads et laissez le thread principal traiter les tâches en file d'attente à partir d'une file d'attente de travaux.

I a utilisé un fil de minuterieet un fil d'entrée d'utilisateur pour simuler 2 fils produisant des emplois. Vous pouvez implémenter vos événements TCP pour simplement mettre en file d'attente un travail dans la file d'attente. Vous devez stocker tous les objets pertinents en tant qu'arguments dans votre travail pour un traitement ultérieur. Vous devez également définir une fonction appelée par le travail, qui s'exécutera dans le thread principal.

Le thread principal est utilisé ici uniquement pour la mise en file d'attente des tâches et leur traitement, mais vous pouvez utiliser n'importe quel autre thread à cette fin si vous améliorez un peu ce code.

Vous pouvez même implémenter un traitement multi-thread, sur lequel plus de threads de traitement sont dédoublés à partir de la même file d'attente. Soyez conscient que cela apporte de nouveaux problèmes de concurrence que vous pourriez avoir à traiter. C'est l'inconvénient de gagner beaucoup plus de puissance de traitement dans votre application. Certains scénarios conviennent pour le traitement multi-thread (par exemple, le traitement vidéo/image) alors que d'autres ne le sont pas.

Le code ci-dessous est un exemple de travail complet écrit dans un Visual Studio 2017, DotNET 4.6.1 projet d'application console, . Copiez, collez et appuyez sur F5.

using System; 
using System.Collections.Concurrent; 
using System.Diagnostics; 
using System.Threading; 

// Compiled and tested in: Visual Studio 2017, DotNET 4.6.1 

namespace MyNamespace 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      MyApplication app = new MyApplication(); 
      app.Run(); 
     } 
    } 

    public class MyApplication 
    { 
     private BlockingCollection<Job> JobQueue = new BlockingCollection<Job>(); 
     private CancellationTokenSource JobCancellationTokenSource = new CancellationTokenSource(); 
     private CancellationToken JobCancellationToken; 
     private Timer Timer; 
     private Thread UserInputThread; 



     public void Run() 
     { 
      // Give a name to the main thread: 
      Thread.CurrentThread.Name = "Main"; 

      // Fires a Timer thread: 
      Timer = new Timer(new TimerCallback(TimerCallback), null, 1000, 2000); 

      // Fires a thread to read user inputs: 
      UserInputThread = new Thread(new ThreadStart(ReadUserInputs)) 
      { 
       Name = "UserInputs", 
       IsBackground = true 
      }; 
      UserInputThread.Start(); 

      // Prepares a token to cancel the job queue: 
      JobCancellationToken = JobCancellationTokenSource.Token; 

      // Start processing jobs: 
      ProcessJobs(); 

      // Clean up: 
      JobQueue.Dispose(); 
      Timer.Dispose(); 
      UserInputThread.Abort(); 

      Console.WriteLine("Done."); 
     } 



     private void ProcessJobs() 
     { 
      try 
      { 
       // Checks if the blocking collection is still up for dequeueing: 
       while (!JobQueue.IsCompleted) 
       { 
        // The following line blocks the thread until a job is available or throws an exception in case the token is cancelled: 
        JobQueue.Take(JobCancellationToken).Run(); 
       } 
      } 
      catch { } 
     } 



     private void ReadUserInputs() 
     { 
      // User input thread is running here. 
      ConsoleKey key = ConsoleKey.Enter; 

      // Reads user inputs and queue them for processing until the escape key is pressed: 
      while ((key = Console.ReadKey(true).Key) != ConsoleKey.Escape) 
      { 
       Job userInputJob = new Job("UserInput", this, new Action<ConsoleKey>(ProcessUserInputs), key); 
       JobQueue.Add(userInputJob); 
      } 
      // Stops processing the JobQueue: 
      JobCancellationTokenSource.Cancel(); 
     } 

     private void ProcessUserInputs(ConsoleKey key) 
     { 
      // Main thread is running here. 
      Console.WriteLine($"You just typed '{key}'. (Thread: {Thread.CurrentThread.Name})"); 
     } 



     private void TimerCallback(object param) 
     { 
      // Timer thread is running here. 
      Job job = new Job("TimerJob", this, new Action<string>(ProcessTimer), "A job from timer callback was processed."); 
      JobQueue.TryAdd(job); // Just enqueues the job for later processing 
     } 

     private void ProcessTimer(string message) 
     { 
      // Main thread is running here. 
      Console.WriteLine($"{message} (Thread: {Thread.CurrentThread.Name})"); 
     } 
    } 



    /// <summary> 
    /// The Job class wraps an object's method call, with or without arguments. This method is called later, during the Job execution. 
    /// </summary> 
    public class Job 
    { 
     public string Name { get; } 
     private object TargetObject; 
     private Delegate TargetMethod; 
     private object[] Arguments; 

     public Job(string name, object obj, Delegate method, params object[] args) 
     { 
      Name = name; 
      TargetObject = obj; 
      TargetMethod = method; 
      Arguments = args; 
     } 

     public void Run() 
     { 
      try 
      { 
       TargetMethod.Method.Invoke(TargetObject, Arguments); 
      } 
      catch(Exception ex) 
      { 
       Debug.WriteLine($"Unexpected error running job '{Name}': {ex}"); 
      } 
     } 

    } 
} 
+0

Salut Daniel très joli gabarit, merci! – uhwgmxorg