2011-10-13 85 views
5

我有一个c#控制台应用程序,最多可创建5个线程。C#多线程控制台应用程序 - 控制台在线程完成前退出

线程执行正常,但UI线程在完成其工作时关闭。

只要侧线程运行,有没有办法让主UI线程运行?

foreach (var url in urls) 
{ 
    Console.WriteLine("starting thread: " + url); 
    ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(myMethod), url); 
} 

我按照上面的代码开始我的线程。

+0

如果创建了普通线程而不是使用线程池? –

+6

什么版本的.NET?如果.NET 4.0建议使用TPL任务,请将所有任务存储在数组中,然后在退出之前使用Tasks.WaitAll(myTaskArray)。 –

+0

我认为线程需要'BackgroundWorker = false' – IAbstract

回答

6

如果您使用的是.NET 4.0:

var tasks = new List<Task>(); 

foreach(var url in urls) 
{ 
    tasks.Add(Task.Factory.StartNew(myMethod, url)); 
} 

// do other stuff... 

// On shutdown, give yourself X number of seconds to wait for them to complete... 
Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(30)); 
+3

Parallel.ForEach()在1行中做了所有这些... –

2

啊 - 线程池为背景。它排队,但是你的程序结束了。成品。程序终止。

阅读信号量(WaitSignal)并等待 - 当所有信号都表示主线程可以继续时,结束时回调中的线程结束信号。

8

ThreadPool中的线程是后台线程,这意味着退出的应用程序不会等待它们完成。

您有几种选择:

  • 等待与例如信号
  • 等待与睡眠计数器(),很粗糙,但OK了一个简单的控制台应用程序。
  • 使用TPL,Parallel.ForEach(urls, url => MyMethod(url));
+1

对于'Parallel.ForEach(url,url => MyMethod(url))'+1。 –

+0

+1,但我不会推荐Counter + Sleep ..值得注意的是可以使用'CountDownEvent'。 – Kiril

+0

@Lirik CountDownEv是Fx4 +,那么你不妨使用TPL。 –

0

最简单的劈解决您的问题。

在程序类:

static volatile int ThreadsComplete = 0; 

在你的 “myMethod的” 末返回之前:

//ThreadsComplete++; //*edit* for safety's sake 
Interlocked.Increment(ref ThreadsComplete); 

在main方法返回/前结束:

while(ThreadsComplete < urls.Count) { Thread.Sleep(10); } 

上面实质上是一个WaitForAll同步方法。

+0

这是一个很好的解决方案,易于实现,谢谢。 –

+2

这不是一个好的解决方案。这是一个易于使用的黑客。 –

+1

这就是为什么你有一个'CountdownEvent' ...没有必要循环或睡觉,这是不好的做法,无论如何等待。 – Kiril

-1
在主

var m = new ManualResetEvent(false); 
// do something 
foreach (var url in urls) 
{ 
    Console.WriteLine("starting thread: " + url); 
    ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(myMethod), url); 
} 
m.WaitOne(); 


private static void myMethod(object obj) 
{ 
    try{ 
    // do smt 
    } 
    finally { 
    m.Set(); 
    } 
} 
+0

没有这个代码不保证等待**所有**线程。 –

+0

如果他将'ManualResetEvent'更改为'CountDownEvent',那么这将是一个很好的解决方案。 – Kiril

+0

@Lirik如果有足够的改变,它也可以写一首诗歌 –

0

如果你使用.NET 4则:

urls.AsParallel().ForAll(MyMethod); 

到.NET 4,然后开始各个线程,让他们在一个列表和电话加入之前( )。在主线程退出后,工作者不是后台的这个事实会使他们活着,但Join()更加明确。

 List<Thread> workers = new List<Thread>(); 
     foreach(var url in urls) 
     { 
      Thread t = new Thread(MyMethod) {IsBackground = false}; 
      workers.Add(t); 
      t.Start(url); 
     } 

     foreach (var worker in workers) 
     { 
      worker.Join(); 
     }