我有一个“threader”类,它抛弃了执行进程的线程。线程在threader类中有一个回调方法,在完成后调用它们。我的问题是我怎么知道线程器抛出的所有线程何时完成?
答案 0 :(得分:9)
如果你计算你已经启动了多少个线程,你可以在线程启动时增加计数,并在线程完成时减少它。
然后,当计数达到零时,您就知道所有线程都已完成。
在处理短期线程时需要注意,以确保在递减计数器之前允许计数器递增。需要使用某种锁定或Interlocked.Increment
和Decrement
来修改计数器变量。 Source
答案 1 :(得分:3)
您可以为活动的线程数保留一个简单的计数器。或者你可以让线程在开始工作之前在集合中注册(添加)并在完成后删除。
答案 2 :(得分:1)
计数有效,但可能比你想象的更难实现...确保在线程内的finally
块中进行减量并同步(lock
)访问计数器(I知道,它应该是原子的,但不过......)。
如果您只创建一些线程并且还有线程实例,那么您也可以在每个实例中使用Thread.Join。即使线程在调用join之前终止(但仍然在清理实例之前),这仍然有效。
所以:
foreach( Thread thread in myThreads)
{
thread.join();
}
一旦完成,您确定所有线程都已完成。
HTH
马里奥
答案 3 :(得分:0)
最简单的方法是,如果事先知道将要运行的线程数,可以在回调函数中使用计数器。
如果您不知道线程数,那么您需要一些“处理结束”指示器来设置一个布尔值以及创建和结束线程的计数器。
如果你不知道将要创建的线程数,一个简单的两个计数器的想法将无法工作(如果第一个线程启动并在创建任何其他线程之前完成,它会错误地认为它是最后一个)。
答案 4 :(得分:0)
在穿线程序线程中检查每个线程的状态。如果所有线程都被停止(或中止),你知道你可以结束主线程。
答案 5 :(得分:0)
您可以使用WaitHandle
s。如果你使用BeginInvoke / EndInvoke来控制你的线程,那就变得更有吸引力了(因为IAsyncResult
带有WaitHandle
)。请记住在WaitAll
通话期间不要超过超过64项的操作系统限制。这是一个扩展方法,使过程更简单:
static class ThreadingExtensions
{
// Possible:
// [ThreadStatic]
// private static List<WaitHandle> PerThreadWaitList;
public const int MaxHandlesPerWait = 64;
public static void WaitAll<T>(this IEnumerable<T> handles, int millisecondsTimeout, int estimatedCount)
where T : WaitHandle
{
// Possible:
// var currentSet = PerThreadWaitList ?? (PerThreadWaitList = new List<WaitHandle>(estimatedCount));
var currentSet = new List<WaitHandle>(Math.Min(estimatedCount, MaxHandlesPerWait));
var timeoutEnd = Environment.TickCount + millisecondsTimeout;
int timeout;
// Wait for items in groups of 64.
foreach (var item in handles)
{
currentSet.Add(item);
if (currentSet.Count == MaxHandlesPerWait)
{
timeout = Timeout.Infinite;
if (millisecondsTimeout >= 0)
{
timeout = timeoutEnd - Environment.TickCount;
if (timeout < 0)
throw new TimeoutException();
}
WaitHandle.WaitAll(currentSet.ToArray(), timeout);
currentSet.Clear();
}
}
// Do the last set.
if (currentSet.Count > 0)
{
timeout = Timeout.Infinite;
if (millisecondsTimeout >= 0)
{
timeout = timeoutEnd - Environment.TickCount;
if (timeout < 0)
timeout = 0;
}
WaitHandle.WaitAll(currentSet.ToArray(), timeout);
currentSet.Clear();
}
}
}
使用示例。
var results = new List<IAsyncResult>();
// Call delegates, e.g.
// results.Add(Foo.BeginInvoke(OnEndInvokeFoo));
results.Select(x => x.AsyncWaitHandle).WaitAll(Timeout.Infinite, results.Count);
答案 6 :(得分:0)
线程计数器的示例代码
long counter = 0;
void ThreadEntryPoint()
{
try
{
...
//
}
finally
{
// Decrement counter
Interlocked.Decrement(ref counter);
}
}
void MainThread()
{
// Start worers
for(...)
{
// Increment threads couter
Interlocked.Increment(ref counter);
((Action)ThreadEntryPoint).BeginInvoke(null, null);
}
// Wait until counter is equal to 0
while(Interlocked.Read(ref counter) != 0)
{
Thread.Sleep(0);
}
}