Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

В следующем фрагменте кода основной поток вызывает 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.

Для отличного введения в потоки я рекомендую прочитать Joe Albahari бесплатно Threading in С#

Ответ 3

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

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

В соответствии с комментарием Arafangion ниже, важно также присоединиться к потокам, если вам нужно сделать код очистки/домашнего хозяйства после создания потока.

Ответ 4

Это очень простая программа для демонстрации использования Thread 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.Run с удалением комментария thread1.Join(): Результат должен быть всегда более 1.because thread1.Join() уволен, а поток 1 должен быть закончен, прежде чем получить сумму.

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

Ответ 5

Добавление задержки в 300 мс в методе "Образец" и задержка в 400 мс в "Sample2" из сообщения devopsEMK упростит понимание.

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

Ответ 6

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

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