2010-08-27 128 views
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(); 
    } 

与经纬(= 100,150,255等...),但我不能学多少线程工作。执行时间。

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

+0

我很难想象一个应用程序,其中255个相同的线程是最优的。请记住,在任何给定时间可以运行系统的最大线程数=目标硬件中独立CPU内核的数量。 fwiw这是我的经验(Win XP SP2),在单个进程中大约120次后线程创建失败。这是在每个基于套接字的应用程序客户端使用一个线程实现的测试应用程序中。没办法,我会以这种方式实现实际的生产代码。 – 2010-08-30 17:18:53

+0

我正在研究网络应用程序,所以我的线程花费了很多时间。和我这是不是一个超载的CPU – Rapunzo 2010-09-03 15:05:57

回答

0

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

+0

你可以扩大什么是“关键部分受保护的单一变量”?以及如何使用 – Rapunzo 2010-08-27 14:44:18

+0

以下是一些示例和定义:http://en.wikipedia.org/wiki/Critical_section – 2010-08-28 13:32:10

1

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

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

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

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

+0

我尝试了这一点,但阻止了进度。 – Rapunzo 2010-08-27 12:32:20

+0

@Rununzo - 的确,这就是要点。 'Thread.Join'是一个阻塞调用 - 因此'Console.WriteLine'将不会执行,直到所有线程完成。您可以在另一个线程上运行这段代码,并根据您选择的通知机制进行适当的同步。为了简单起见,我在这里使用了'Console.WriteLine'。 – 2010-08-27 14:10:27

1

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

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

这里有一个介绍到异步编程: http://msdn.microsoft.com/en-us/library/aa719598%28v=VS.71%29.aspx

+0

你能解释一下异步方法吗? – Rapunzo 2010-08-27 12:33:47

+0

您使用BeginInvoke()调用方法而不是直接调用它 – Jerome 2010-08-27 13:00:22

1

首先,我要指出的是创造100,150,255,等线程可能不是一个好主意。使用ThreadPoolTask类(如果使用.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。

A CountdownEvent等待其内部计数达到零。如果您想使用ThreadPool,此方法更适合。如果你不使用.NET 4.0,你可以通过Joe Albahari's website获得一个非常简单的实现。

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

是在.net 3.5中定义的countdownevent? – Rapunzo 2010-08-27 14:22:03

+0

不,我更新了我的答案,包含一个简单实现的链接。 – 2010-08-27 14:35:22

1

你一定要使用Task类本或类似Parallel.ForEach更高层次的概念。直接使用Thread类非常痛苦。

我最近wrote a blog post比较各种异步方法,按从最佳(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); 
+0

我尝试添加使用System.Threading.Tasks;到我的项目,但得到一个错误:名称空间'System.Threading'中不存在类型或命名空间名称'Tasks'(您是否缺少程序集引用?) – Rapunzo 2010-08-27 14:05:27

+0

要使用Task类,您需要.NET 4.0或用于.NET 3.5的[Rx库](http://msdn.microsoft.com/zh-cn/devlabs/ee794896.aspx)。 – 2010-08-27 15:10:43

1

添加了代表对搜索器,并从你的主线程传递一个回调方法,当它完成每个线程将调用。在启动每个线程时,将其添加到由线程的ManagedThreadId键入的字典中。当每个线程完成时,回调会从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); 
      } 
     } 

如果你有多个线程比你想在同一时间运行,把它们放入一个队列,并剥离掉相应的旧的线程结束(使用回调)。

+0

感谢您的解决方案,但(activeThreads.Count == 0)不工作healty,很多次失败! 这里是我的代码 如果((activeThreads.Count)== 0){ J ++; progressBar1.Value = 0; btnSearch.Enabled = true; } 在这种情况下progressbar1。价值获得0和多次成长后,再次开始0。我不能确定线程已经完成 – Rapunzo 2010-09-03 15:02:08

+0

@Rapunzo - 发生的事情是,一旦创建了每个线程,就开始创建每个线程,并且在后面的线程开始之前初始线程已经完成。解决这个问题的快速方法是将t.Start()移动到第二个循环,以便在启动它们之前创建它们。更优雅的方法是将创建的线程放在队列中,并使用生产者 - 消费者模式读取它们。这也可以让你控制并发线程的数量。 – 2010-09-03 17:35:35