developer tip

C # : 모든 스레드가 완료 될 때까지 대기

optionbox 2020. 11. 25. 07:52
반응형

C # : 모든 스레드가 완료 될 때까지 대기


작성중인 코드에서 공통 패턴으로 실행 중입니다. 여기서 그룹의 모든 스레드가 완료 될 때까지 기다려야하며 시간 제한이 있습니다. 타임 아웃은 모든 스레드가 완료하는 데 필요한 시간 이므로 가능한 타임 아웃이 timeout * numThreads이므로 각 스레드에 대해 단순히 thread.Join (timeout)을 수행하면 작동하지 않습니다.

지금은 다음과 같은 작업을 수행합니다.

var threadFinishEvents = new List<EventWaitHandle>();

foreach (DataObject data in dataList)
{
    // Create local variables for the thread delegate
    var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
    threadFinishEvents.Add(threadFinish);

    var localData = (DataObject) data.Clone();
    var thread = new Thread(
        delegate()
        {
            DoThreadStuff(localData);
            threadFinish.Set();
        }
    );
    thread.Start();
}

Mutex.WaitAll(threadFinishEvents.ToArray(), timeout);

그러나 이런 종류의 경우에는 더 간단한 관용구가 있어야 할 것 같습니다.


여전히 Join 사용이 더 간단하다고 생각합니다. 예상 완료 시간 (Now + timeout)을 기록한 다음 루프에서 다음을 수행합니다.

if(!thread.Join(End-now))
    throw new NotFinishedInTime();

.NET 4.0에서는 System.Threading.Tasks 작업이 훨씬 더 쉬워졌습니다. 나를 위해 안정적으로 작동하는 스핀 대기 루프가 있습니다. 모든 작업이 완료 될 때까지 메인 스레드를 차단합니다. Task.WaitAll있지만 항상 저에게 효과가있는 것은 아닙니다.

        for (int i = 0; i < N; i++)
        {
            tasks[i] = Task.Factory.StartNew(() =>
            {               
                 DoThreadStuff(localData);
            });
        }
        while (tasks.Any(t => !t.IsCompleted)) { } //spin wait

질문이 부딪 혔으므로 계속해서 내 솔루션을 게시하겠습니다.

using (var finished = new CountdownEvent(1)) 
{ 
  for (DataObject data in dataList) 
  {   
    finished.AddCount();
    var localData = (DataObject)data.Clone(); 
    var thread = new Thread( 
        delegate() 
        {
          try
          {
            DoThreadStuff(localData); 
            threadFinish.Set();
          }
          finally
          {
            finished.Signal();
          }
        } 
    ); 
    thread.Start(); 
  }  
  finished.Signal(); 
  finished.Wait(YOUR_TIMEOUT); 
} 

내 머리 꼭대기에서 Thread.Join (timeout) 만하고 총 제한 시간에서 참여하는 데 걸린 시간을 제거하지 않는 이유는 무엇입니까?

// pseudo-c#:

TimeSpan timeout = timeoutPerThread * threads.Count();

foreach (Thread thread in threads)
{
    DateTime start = DateTime.Now;

    if (!thread.Join(timeout))
        throw new TimeoutException();

    timeout -= (DateTime.Now - start);
}

편집 : 코드는 이제 덜 유사합니다. +4를 수정 한 답변이 정확히 동일 할 때 답변 -2를 수정하는 이유를 이해하지 못합니다.


이것은 질문에 대답하지 않지만 (시간 제한 없음), 컬렉션의 모든 스레드를 기다리는 매우 간단한 확장 메서드를 만들었습니다.

using System.Collections.Generic;
using System.Threading;
namespace Extensions
{
    public static class ThreadExtension
    {
        public static void WaitAll(this IEnumerable<Thread> threads)
        {
            if(threads!=null)
            {
                foreach(Thread thread in threads)
                { thread.Join(); }
            }
        }
    }
}

그런 다음 간단히 전화하십시오.

List<Thread> threads=new List<Thread>();
//Add your threads to this collection
threads.WaitAll();

This may not be an option for you, but if you can use the Parallel Extension for .NET then you could use Tasks instead of raw threads and then use Task.WaitAll() to wait for them to complete.


I was tying to figure out how to do this but i could not get any answers from google. I know this is an old thread but here was my solution:

Use the following class:

class ThreadWaiter
    {
        private int _numThreads = 0;
        private int _spinTime;

        public ThreadWaiter(int SpinTime)
        {
            this._spinTime = SpinTime;
        }

        public void AddThreads(int numThreads)
        {
            _numThreads += numThreads;
        }

        public void RemoveThread()
        {
            if (_numThreads > 0)
            {
                _numThreads--;
            }
        }

        public void Wait()
        {
            while (_numThreads != 0)
            {
                System.Threading.Thread.Sleep(_spinTime);
            }
        }
    }
  1. Call Addthreads(int numThreads) before executing a thread(s).
  2. Call RemoveThread() after each one has completed.
  3. Use Wait() at the point that you want to wait for all the threads to complete before continuing

I read the book C# 4.0: The Complete Reference of Herbert Schildt. The author use join to give a solution :

class MyThread
    {
        public int Count;
        public Thread Thrd;
        public MyThread(string name)
        {
            Count = 0;
            Thrd = new Thread(this.Run);
            Thrd.Name = name;
            Thrd.Start();
        }
        // Entry point of thread.
        void Run()
        {
            Console.WriteLine(Thrd.Name + " starting.");
            do
            {
                Thread.Sleep(500);
                Console.WriteLine("In " + Thrd.Name +
                ", Count is " + Count);
                Count++;
            } while (Count < 10);
            Console.WriteLine(Thrd.Name + " terminating.");
        }
    }
    // Use Join() to wait for threads to end.
    class JoinThreads
    {
        static void Main()
        {
            Console.WriteLine("Main thread starting.");
            // Construct three threads.
            MyThread mt1 = new MyThread("Child #1");
            MyThread mt2 = new MyThread("Child #2");
            MyThread mt3 = new MyThread("Child #3");
            mt1.Thrd.Join();
            Console.WriteLine("Child #1 joined.");
            mt2.Thrd.Join();
            Console.WriteLine("Child #2 joined.");
            mt3.Thrd.Join();
            Console.WriteLine("Child #3 joined.");
            Console.WriteLine("Main thread ending.");
            Console.ReadKey();
        }
    }

Possible solution:

var tasks = dataList
    .Select(data => Task.Factory.StartNew(arg => DoThreadStuff(data), TaskContinuationOptions.LongRunning | TaskContinuationOptions.PreferFairness))
    .ToArray();

var timeout = TimeSpan.FromMinutes(1);
Task.WaitAll(tasks, timeout);

Assuming dataList is the list of items and each item needs to be processed in a separate thread.

참고URL : https://stackoverflow.com/questions/263116/c-waiting-for-all-threads-to-complete

반응형