3

我将我的线程创建为

 for (int i = 0; i < threadCount; i++)
 {
     Searcher src = new Searcher(i, this);

     threads[i] = new Thread(new ThreadStart(src.getIpRange));
     threads[i].Name = string.Format(i.ToString());
  }

  foreach (Thread t in threads)
  {
     t.Start();
  }

使用 threadCount(= 100, 150, 255 等...) 但我不知道有多少线程在工作。在执行时间。

我想控制所有线程何时完成工作。并给我一条消息,例如“所有线程都已死,作业已完成...”,例如 backgroundWorker 的 RunWorkerCompleted 事件

4

6 回答 6

1

首先,我必须指出,创建 100、150、255 等线程可能不是一个好主意。最好使用ThreadPoolorTask类(如果使用 .NET 4.0)。除此之外,还有两种完善的方法可以等待所有线程完成。

加入线程。

Thread.Join阻塞直到目标线程完成。

for (int i = 0; i < threadCount; i++) 
{ 
   Searcher src = new Searcher(i, this); 
   threads[i] = new Thread(new ThreadStart(src.getIpRange)); 
   threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
   t.Start(); 
} 

foreach (Thread t in threads)
{
   t.Join(); 
}

使用倒计时事件。

CountdownEvent一直等到其内部计数达到零。如果您想使用ThreadPool. 如果您不使用 .NET 4.0,您可以在Joe Albahari 的网站上获得一个非常简单的实现。

var finished = new CountdownEvent(1);

for (int i = 0; i < threadCount; i++) 
{ 
   finished.AddCount();
   Searcher src = new Searcher(i, this); 
   threads[i] = new Thread(
     () =>
     {
        try
        {
          src.getIpRange();
        }
        finally
        {
          finished.Signal();
        }
     }
   threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
   t.Start(); 
} 

finished.Signal();
finished.WaitOne();
于 2010-08-27T13:10:15.447 回答
1

您肯定希望将Task类用于此或更高级别的概念,例如Parallel.ForEach. 直接使用Thread类是相当痛苦的。

我最近写了一篇博客文章,比较了各种异步方法,按从最好 ( Task) 到最差 ( Thread) 的顺序列出。

这是一个使用 的示例Task,展示了您想要做什么:

// Start all tasks
var threads = new Task[threadCount];
for (int i = 0; i < threadCount; i++) 
{ 
  Searcher src = new Searcher(i, this); 
  threads[i] = Task.Factory.StartNew(src.getIpRange);
}

// How many are running right now?
var runningCount = threads.Count(x => x.Status == TaskStatus.Running);

// Register a callback when they have all completed (this does not block)
Task.Factory.ContinueWhenAll(threads, MyCallback);
于 2010-08-27T13:24:16.737 回答
1

向 Searcher 添加一个委托,并从主线程向其传递一个回调方法,每个线程在完成时都会调用该方法。启动每个线程时,将其添加到由线程的 ManagedThreadId 键入的 Dictionary 中。当每个线程完成时,回调从 Dictionary 中删除线程并检查计数是否为零。

        Dictionary<int, Thread> activeThreads = new Dictionary<int, Thread>();            

           for (int i = 0; i < threadCount; i++)
            {
                Searcher src = new Searcher(i, this);
                src.Done = new SearcherDoneDelegate(ThreadDone);
                threads[i] = new Thread(new ThreadStart(src.getIpRange));
                threads[i].Name = string.Format(i.ToString());
            }

            foreach (Thread t in threads)
            {
                lock (activeThreads)
                {
                    activeThreads.Add(t.ManagedThreadId, t);
                }
                t.Start();
            }


        }
        public void ThreadDone(int threadIdArg)
        {
            lock (activeThreads)
            {
                activeThreads.Remove(threadIdArg);
                if (activeThreads.Count == 0)
                {
                    // all done
                }
            }
        }

        public delegate void SearcherDoneDelegate(int threadIdArg);
        public static object locker = new object();



        public class Searcher
        {
            public SearcherDoneDelegate Done { get; set; }
            public void getIpRange()
            {
                Done(Thread.CurrentThread.ManagedThreadId);
            }
        }

如果您的线程多于一次运行,请将它们放入队列并在旧线程完成时将它们剥离(使用回调)。

于 2010-08-27T16:46:16.940 回答
1

确定所有线程何时完成很简单。

for (int i = 0; i < threadCount; i++)
{
    threads[i].Join();
}

Console.WriteLine("All threads are done!");

你能详细说明你的其他要求吗?

于 2010-08-27T12:19:41.700 回答
1

您可以检查ThreadState线程的属性。

使用异步方法可能会更好。这为您提供了一个WaitHandle对象,您可以使用它WaitHandle.WaitAll来等待所有异步方法完成。

这是异步编程的介绍:http: //msdn.microsoft.com/en-us/library/aa719598%28v=VS.71%29.aspx

于 2010-08-27T12:19:50.077 回答
0

为什么不能使用临界区保护的单个变量来控制多个活动线程?线程函数可以修改这个变量(当然已经进入了临界区)。

于 2010-08-27T12:17:48.113 回答