【发布时间】:2012-07-01 11:52:45
【问题描述】:
使用 ThreadPool 实现以下嵌套异步循环的幼稚实现:
ThreadPool.SetMaxThreads(10, 10);
CountdownEvent icnt = new CountdownEvent(1);
for (int i = 0; i < 50; i++)
{
icnt.AddCount();
ThreadPool.QueueUserWorkItem((inum) =>
{
Console.WriteLine("i" + inum + " scheduled...");
Thread.Sleep(10000); // simulated i/o
CountdownEvent jcnt = new CountdownEvent(1);
for (int j = 0; j < 50; j++)
{
jcnt.AddCount();
ThreadPool.QueueUserWorkItem((jnum) =>
{
Console.WriteLine("j" + jnum + " scheduled...");
Thread.Sleep(20000); // simulated i/o
jcnt.Signal();
Console.WriteLine("j" + jnum + " complete.");
}, j);
}
jcnt.Signal();
jcnt.Wait();
icnt.Signal();
Console.WriteLine("i" + inum + " complete.");
}, i);
}
icnt.Signal();
icnt.Wait();
现在,您永远不会使用此模式(它会在启动时死锁),但它确实演示了您可以使用线程池导致的特定死锁 - 通过在阻塞线程消耗完整个线程后等待嵌套线程完成时阻塞游泳池。
我想知道使用嵌套的 Parallel.For 版本是否存在产生类似有害行为的潜在风险:
Parallel.For(1, 50, (i) =>
{
Console.WriteLine("i" + i + " scheduled...");
Thread.Sleep(10000); // simulated i/o
Parallel.For(1, 5, (j) =>
{
Thread.Sleep(20000); // simulated i/o
Console.WriteLine("j" + j + " complete.");
});
Console.WriteLine("i" + i + " complete.");
});
显然调度机制要复杂得多(而且我还没有看到这个版本出现死锁),但潜在的风险似乎仍然潜伏在那里。理论上是否有可能通过依赖嵌套线程来使 Parallel.For 使用的池干涸到造成死锁的程度?即 Parallel.For 为延迟后安排的作业保留的线程数是否有限制?
【问题讨论】:
标签: c# multithreading threadpool task-parallel-library parallel-extensions