web-dev-qa-db-fra.com

Multithreading: Quand utiliser une jointure?

Je vois en ligne qu'il indique que j'utilise myThread.Join(); lorsque je souhaite bloquer mon thread jusqu'à ce qu'un autre thread se termine. (L'une des choses que je ne comprends pas, c'est ce qui se passe si j'ai plusieurs threads).

Mais en général, je ne comprends pas quand j'utilise .Join() ou une condition pour laquelle c'est utile. Quelqu'un peut-il m'expliquer s'il vous plaît comme je suis une quatrième niveleuse? L'explication très simple à comprendre obtiendra ma réponse vote.

56
foreyez

Supposons que vous souhaitiez démarrer des threads de travail pour effectuer un calcul, puis faire quelque chose avec tous les résultats.

List<Thread> workerThreads = new List<Thread>();
List<int> results = new List<int>();

for (int i = 0; i < 5; i++) {
    Thread thread = new Thread(() => {
        Thread.Sleep(new Random().Next(1000, 5000));
        lock (results) {
            results.Add(new Random().Next(1, 10));
        }
    });
    workerThreads.Add(thread);
    thread.Start();
}

// Wait for all the threads to finish so that the results list is populated.
// If a thread is already finished when Join is called, Join will return immediately.
foreach (Thread thread in workerThreads) {
    thread.Join();
}

Debug.WriteLine("Sum of results: " + results.Sum());

Oh oui, et n'utilisez pas Random comme ça, j'essayais juste d'écrire un exemple minimal, facilement compréhensible. Si vous créez de nouvelles instances aléatoires trop rapprochées dans le temps, cela ne finit pas vraiment par être aléatoire, car le germe est basé sur l'horloge.

63
J.D.

Dans l'extrait de code suivant, le thread principal appelle Join () ce qui le fait attendre que tous les threads générés se terminent:

static void Main()
{
    Thread regularThread = new Thread(ThreadMethod);
    regularThread.Start();

    Thread regularThread2 = new Thread(ThreadMethod2);
    regularThread2.Start();

    // Wait for spawned threads to end.
    regularThread.Join();
    Console.WriteLine("regularThread returned.");

    regularThread2.Join();
    Console.WriteLine("regularThread2 returned.");
}

Notez que si vous avez également créé un thread du pool de threads (à l'aide de QueueUserWorkItem par exemple), Join n'attendra pas ce thread d'arrière-plan. Vous auriez besoin d'implémenter un autre mécanisme tel que l'utilisation d'un AutoResetEvent.

Pour une excellente introduction au threading, je vous recommande de lire free/de Joe Albahari Threading in C #

18
Mitch Wheat

C'est un programme très simple pour démontrer l'utilisation de Thread Join. Veuillez suivre mes commentaires pour une meilleure compréhension. Écrivez ce programme tel quel.

    using System;
    using System.Threading;


    namespace ThreadSample
    {
        class Program
        {
            static Thread thread1, thread2;
            static int sum=0;
            static void Main(string[] args)
            {
                start();
                Console.ReadKey();
            }
            private static void Sample() { sum = sum + 1; }
            private static void Sample2() { sum = sum + 10; }

            private static void start() 
            {    
                thread1 = new Thread(new ThreadStart(Sample));
                thread2 = new Thread(new ThreadStart(Sample2));
                thread1.Start();
                thread2.Start();
             // thread1.Join(); 
             // thread2.Join();
                Console.WriteLine(sum);
                Console.WriteLine();
            }
       }
}

1.Première fois tel quel (avec commentaires): Alors le résultat sera 0 (valeur initiale) ou 1 (lorsque le fil 1 sera terminé) ou 10 (ou le fil sera terminé)

2.Exécuter avec supprimer le commentaire thread1.Join(): Le résultat doit toujours être supérieur à 1 . Parce que thread1.Join() a été déclenché et que le thread 1 doit être terminé avant d'obtenir la somme.

3.Exécutez avec en supprimant tous les commentaires: Le résultat doit toujours être 11

11
Elshan

La jointure est utilisée principalement lorsque vous devez attendre qu'un thread (ou un groupe d'entre eux) se termine avant de procéder à votre code. 

Pour cette raison, est également particulièrement utile lorsque vous devez collecter le résultat d'une exécution de thread.

Selon le commentaire Arafangion ci-dessous, il est également important de rejoindre les discussions si vous devez effectuer un code de nettoyage/nettoyage après avoir créé un fil.

9
Lorenzo

Join s'assurera que les marches au-dessus de la ligne sont exécutées avant d'exécuter les lignes ci-dessous.

3
nayanajith

Ajouter un délai de 300 ms dans la méthode "Sample" et un délai de 400 ms dans "Sample2" de la publication de devopsEMK le rendrait plus facile à comprendre. 

Ce faisant, vous pouvez observer cela en supprimant le commentaire de "thread1.Join ();" le thread principal attend la fin du "thread1" et seulement après que passe.

0
Paul S.

Un autre exemple, lorsque votre thread de travail, par exemple, lit un flux d'entrée alors que la méthode de lecture peut s'exécuter à l'infini et que vous souhaitez éviter cela - en appliquant un délai d'attente à l'aide d'un autre thread de surveillance:

// worker thread
var worker = new Thread(() => {
    Trace.WriteLine("Reading from stream");

    // here is the critical area of thread, where the real stuff happens
    // Sleep is just an example, simulating any real operation
    Thread.Sleep(10000);

    Trace.WriteLine("Reading finished");
}) { Name = "Worker" };
Trace.WriteLine("Starting worker thread...");
worker.Start();

// watchdog thread
ThreadPool.QueueUserWorkItem((o) => {
    var timeOut = 5000;
    if (!worker.Join(timeOut))
    {
        Trace.WriteLine("Killing worker thread after " + timeOut + " milliseconds!");
        worker.Abort();
    }
});
0
Ladislav