【问题标题】:When All Threads Are Complete当所有线程都完成时
【发布时间】:2011-03-13 14:30:27
【问题描述】:

这是我第一次真正尝试使用多线程,我想知道如何判断我的所有任务组何时完成运行:

for (int i = 0; i < taskGroups.Count(); i++) {
    ThreadStart t = delegate { RunThread(taskGroups[i]); };
    new Thread(t).Start();
}
if(allThreadsComplete){ //???

}

任何帮助将不胜感激

附录:

ThreadStart[] threads = new ThreadStart[taskGroups.Count()];
for (int i = 0; i < taskGroups.Count(); i++) {
    threads[i] = new ThreadStart[]
    threads[i] = delegate { RunThread(taskGroups[i]); };
    new Thread(t).Start();
}
bool threadsComplete = false;
while(!threadsComplete){
    for(int i=0;i<taskGroups.Count();i++){
        if(threads[i].State == complete)
        threadsComplete = true;
    }
}

【问题讨论】:

  • 你的i 变量被所有线程共享。
  • 如果从 Slaks 的评论中不清楚 - 在调用 RunThread 时,您的两个(或更多)线程可能会启动并观察到相同的 i 值 -几乎可以肯定是你不想要的东西。
  • 此外,如果您正在学习未来的开发工作,最好学习使用任务和任务并行库进行多线程 - 这是一组更新的线程原语对于 .NET。
  • 是共享i,我应该在一个循环中创建所有任务,在一个单独的循环中启动所有任务吗?

标签: c# multithreading


【解决方案1】:

您需要存储所有线程,然后调用 Thread.Join()。

类似这样的:

List<Thread> threads = new List<Thread>();
for (int i = 0; i < taskGroups.Count(); i++) {
   int temp = i; //This fixes the issue with i being shared
   Thread thread = new Thread(() => RunThread(taskGroups[temp]));
   threads.Add(thread);
   thread.Start();
}

foreach (var thread in threads) {
    thread.Join();
}

【讨论】:

  • 在您的 for 循环中,如何将带有参数的方法分配给特定线程?比如,thread.doWork=someMethod(aParameter)
  • 线程 thread = new Thread(() => someMethod(aParameter));如果它抱怨您的委托类型,请在 Thread 构造函数中强制转换为 (ThreadStart)。
  • 我看了上面那个人的cmets。将“i”存储在循环内的局部变量中以解决您的问题。我会尽快更新我的答案。
  • 乔纳森,谢谢!那个临时变量把它修好了!
【解决方案2】:

如果您使用的是 3.5,那么您可以 write your ownCountdownEvent,如果您使用的是 4.0,那么您可以使用内置的 CountdownEvent 来执行以下操作:

CountdownEvent = new CountdownEvent(taskGroups.Count());

for (int i = 0; i < taskGroups.Count(); i++) 
{
    int item = i; // copy i locally
    ThreadStart t = delegate 
    { 
        RunThread(taskGroups[item]); 
        latch.Signal();
    };
    new Thread(t).Start();
}

latch.Wait();

latch.Wait() 将导致您的代码阻塞,直到线程全部完成。此外,您可能希望稍微更改启动线程的方式:

CountdownEvent = new CountdownEvent(taskGroups.Count());

for (int i = 0; i < taskGroups.Count(); i++) 
{
    int item = i; // copy i locally
    Thread t = new Thread(()=>
    { 
        RunThread(taskGroups[item]); 
        latch.Signal();
    });
    t.IsBackground = true;
    t.Start();
}

latch.Wait();

请注意,我将线程设置为后台:这是您的应用程序在退出时挂起并且并非所有线程都已完成(即防止幽灵或守护线程)。

【讨论】:

    【解决方案3】:

    您可以使用Thread.Join 确保每个单独的线程都已完成运行。

    【讨论】:

      【解决方案4】:

      您可以将公共静态整数字段添加到主线程,在每个子线程中,当它完成时将其加一,然后在主线程中等待(在循环中),直到该变量等于 taskGroups.Count()

      【讨论】:

        【解决方案5】:

        首先考虑使用Task切换到新的异步模式。

        无论如何,如果您想等待所有线程,您可以致电Thread.Join

        var threads = new List<Thread>();    
        for (int i = 0; i < taskGroups.Count(); i++) {
            ThreadStart t = delegate { RunThread(taskGroups[i]); };
            var thread = new Thread(t);
            threads.Add(thread);
            thread.Start();
        }
        
        threads.ForEach(a => a.Join());
        

        请记住,您还可以传递一个超时参数,该参数将等待线程完成,前提是它不会超过您传入的时间。

        【讨论】:

        • 如果他要改用“Task”和 .Net 4.0 的东西,为什么不直接使用 Parallel.For 或 Parallel.ForEach?
        • 问他原因 :) 我已经向他展示了如何等待 Thread 类的线程。
        【解决方案6】:

        您可以检查每个Thread 对象的ThreadState 属性。

        【讨论】:

          猜你喜欢
          • 2023-03-25
          • 2015-10-04
          • 1970-01-01
          • 1970-01-01
          • 2014-08-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多