164 votes

Que fait le SynchronizationContext ?

Dans le livre "Programming C#", il y a un exemple de code qui concerne SynchronizationContext :

SynchronizationContext originalContext = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(delegate {
    string text = File.ReadAllText(@"c:\temp\log.txt");
    originalContext.Post(delegate {
        myTextBox.Text = text;
    }, null);
});

Je suis un débutant en matière de fils, alors veuillez répondre en détail. Tout d'abord, je ne sais pas ce que signifie le contexte, ce que le programme sauvegarde dans le originalContext ? Et quand le Post est déclenchée, que va faire le thread de l'interface utilisateur ?
Si je pose des questions stupides, merci de me corriger, merci !

EDIT : Par exemple, que se passe-t-il si j'écris simplement myTextBox.Text = text; dans la méthode, quelle est la différence ?

4voto

Ciro Corvino Points 1232

SynchronizationContext est essentiellement un fournisseur d'exécution de délégués de callback principalement responsable d'assurer que les délégués sont exécutés dans un contexte d'exécution donné après une partie particulière du code. (encapsulé dans un objet Task de .Net TPL) d'un programme a terminé son exécution.

D'un point de vue technique, SC est une simple classe C# qui est orientée pour supporter et fournir sa fonction spécifiquement pour les objets de la bibliothèque Task Parallel.

Chaque application .Net, à l'exception des applications console, possède une implémentation particulière de cette classe basée sur le cadre sous-jacent spécifique, c'est-à-dire WPF, WindowsForm, Asp Net, Silverlight, etc.

L'importance de cet objet est liée à la synchronisation entre les résultats renvoyés par l'exécution asynchrone du code et l'exécution du code dépendant qui attend les résultats de ce travail asynchrone.

Et le mot "context" signifie contexte d'exécution, c'est-à-dire le contexte d'exécution actuel dans lequel le code en attente sera exécuté, c'est-à-dire que la synchronisation entre le code asynchrone et son code en attente se produit dans un contexte d'exécution spécifique, donc cet objet est appelé SynchronizationContext : il représente le contexte d'exécution qui s'occupera de la syncronisation du code asynchrone et de l'exécution du code en attente .

3voto

Marc2001 Points 261

SynchronizationContext nous fournit un moyen de mettre à jour une interface utilisateur à partir d'un thread différent (de manière synchrone via la méthode Send ou asynchrone via la méthode Post).

Regardez l'exemple suivant :

    private void SynchronizationContext SyncContext = SynchronizationContext.Current;
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Thread thread = new Thread(Work1);
        thread.Start(SyncContext);
    }

    private void Work1(object state)
    {
        SynchronizationContext syncContext = state as SynchronizationContext;
        syncContext.Post(UpdateTextBox, syncContext);
    }

    private void UpdateTextBox(object state)
    {
        Thread.Sleep(1000);
        string text = File.ReadAllText(@"c:\temp\log.txt");
        myTextBox.Text = text;
    }

SynchronizationContext.Current renverra le contexte de synchronisation du thread de l'interface utilisateur. Comment puis-je le savoir ? Au début de chaque formulaire ou de chaque application WPF, le contexte est défini sur le thread UI. Si vous créez une application WPF et que vous exécutez mon exemple, vous verrez que lorsque vous cliquez sur le bouton, il dort pendant environ 1 seconde, puis il affiche le contenu du fichier. Vous pourriez vous attendre à ce qu'il ne le fasse pas parce que l'appelant de la méthode UpdateTextBox (qui est Work1) est une méthode passée à un Thread, donc il devrait dormir dans ce thread et non dans le thread principal de l'interface utilisateur, NOPE ! Même si la méthode Work1 est passée à un thread, remarquez qu'elle accepte également un objet qui est le SyncContext. Si vous le regardez, vous verrez que la méthode UpdateTextBox est exécutée par la méthode syncContext.Post et non par la méthode Work1. Jetez un coup d'oeil à ce qui suit :

private void Button_Click(object sender, RoutedEventArgs e) 
{
    Thread.Sleep(1000);
    string text = File.ReadAllText(@"c:\temp\log.txt");
    myTextBox.Text = text;
}

Le dernier exemple et celui-ci s'exécutent de la même manière. Les deux ne bloquent pas l'interface utilisateur pendant qu'ils font leur travail.

En conclusion, considérez le SynchronizationContext comme un thread. Ce n'est pas un thread, il définit un thread (Notez que tous les threads n'ont pas un SyncContext). Chaque fois que nous appelons la méthode Post ou Send pour mettre à jour une IU, c'est comme si nous mettions à jour l'IU normalement depuis le thread principal de l'IU. Si, pour une raison ou une autre, vous devez mettre à jour l'interface utilisateur à partir d'un autre thread, assurez-vous que ce thread possède le SyncContext du thread principal de l'interface utilisateur et appelez simplement la méthode Send ou Post avec la méthode que vous voulez exécuter et tout est prêt.

J'espère que ça t'aidera, mon pote !

1voto

loneshark99 Points 532

Cet exemple est tiré des exemples Linqpad de Joseph Albahari mais il aide vraiment à comprendre ce que fait le contexte de synchronisation.

void WaitForTwoSecondsAsync (Action continuation)
{
    continuation.Dump();
    var syncContext = AsyncOperationManager.SynchronizationContext;
    new Timer (_ => syncContext.Post (o => continuation(), _)).Change (2000, -1);
}

void Main()
{
    Util.CreateSynchronizationContext();
    ("Waiting on thread " + Thread.CurrentThread.ManagedThreadId).Dump();
    for (int i = 0; i < 10; i++)
        WaitForTwoSecondsAsync (() => ("Done on thread " + Thread.CurrentThread.ManagedThreadId).Dump());
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X