Многопоточность: когда я буду использовать соединение?


Я вижу в интернете, что он говорит, что я использую myThread.Join(); когда я хочу заблокировать мой поток, пока другой поток закончит. (Одна из вещей, которые я не понимаю, это то, что если у меня есть несколько потоков).

но вообще, я просто не понимаю, когда я буду использовать .Join() или условие, для которого это полезно. Может кто-нибудь объяснить мне, как я-четвероклассник? Очень простое объяснение, чтобы понять, получит мой ответ голосовать.

7 52

7 ответов:

допустим, вы хотите запустить некоторые рабочие потоки для выполнения какого-то расчета, а затем сделать что-то после этого со всеми результатами.

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());

О да, и не используйте случайные, как это, я просто пытался написать минимальный, легко понятный пример. Это заканчивается не совсем случайным, если вы создаете новые случайные экземпляры слишком близко по времени, так как семя основано на часах.

в следующем фрагменте кода, основной поток звонков Join () что заставляет его ждать завершения всех порожденных потоков:

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.");
}

обратите внимание, что если вы также развернули поток из пула потоков (например, с помощью QueueUserWorkItem), Join не будет ждать этого фонового потока. Вам нужно будет реализовать какой-то другой механизм, такой как использование AutoResetEvent.

для отличного введения в резьбу, я рекомендую прочитать Джо Албахари бесплатно многопоточность в C#

Join используется в основном, когда вам нужно подождать, что поток (или их куча) завершится перед обработкой вашего кода.

по этой причине это также особенно полезно, когда вам нужно собрать результат выполнения потока.

согласно комментарию Arafangion ниже, Также важно присоединиться к потокам, если вам нужно сделать некоторый код очистки/уборки после создания потока.

Это очень простая программа для демонстрации использования потока Join.Пожалуйста, следуйте моим комментариям для лучшего понимания.Напишите эту программу как есть.

    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.Первый раз запустить как есть (с комментариями):тогда результат будет 0 (начальное значение) или 1(когда поток 1 закончен) или 10 (или поток закончен)

2.Бегите с удаление комментария thread1.Join():результат должен быть всегда больше 1.потому что thread1.Join() уволен и поток 1 должен быть закончен, прежде чем получить сумму.

3.Бегите с удаление всех комментариев:результат должен быть всегда 11

Join будет убедиться, что протекторы выше линии выполняется перед выполнением строк ниже.

добавление задержки 300 мс в методе " Sample "и задержки 400 мс в" Sample2 " из сообщения devopsEMK облегчило бы понимание.

таким образом, вы можете наблюдать, что, удалив комментарий из "thread1.Join (); "линия, основной поток ждет завершения "thread1" и только после того, как движется дальше.

другой пример, когда ваш рабочий поток, скажем, читает из входного потока, в то время как метод чтения может работать вечно, и вы хотите как - то избежать этого-применяя тайм-аут с помощью другого сторожевого потока:

// 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();
    }
});