在 c# .Net 3.5 中,如何控制多个 WaitHandles?
Posted
技术标签:
【中文标题】在 c# .Net 3.5 中,如何控制多个 WaitHandles?【英文标题】:In c# .Net 3.5, how can I control multiple WaitHandles? 【发布时间】:2011-08-28 23:33:52 【问题描述】:我有以下情况: 我的应用程序必须从另一个应用程序导入多组数据,时间很关键。 因此,它为每次导入生成一个线程。 所以,假设我有 1 到 10 的进口,其中进口 4 和 5 只能在进口 2 之后的进口 1、6 和 7 以及进口 3 之后的 8、9 和 10 之后运行
导入 1 导入4 导入5 导入 2 导入6 导入7 导入 3 导入8 导入9 导入10搜索 *** 我发现了一些关于等待句柄的答案,但我不确定控制多个等待句柄。
我想创建一个导入/句柄列表并在循环中检查它们,但我不知道如何从那里触发 .set()。
或者为每个父导入创建一个线程并在其中实例化句柄,并且该父线程为每个子导入触发一个线程,但是我不确定处理线程的线程是否正确。
关于如何解决这个问题的任何想法?
更新:
在 Brian Gideon 的回答之后,我想到了:dateSince = Convert.ToDateTime(txtBoxDateSince.Text);
dateTo = Convert.ToDateTime(txtBoxDateTo.Text);
//在时间间隔上循环所有天 而 (DateTime.Compare(dateSince, dateTo)
foreach (ListItem father in checkBoxListFather.Items)
if (father.Selected == true)
processClass process = new processClass();
// This WaitHandle will be used to get the child tasks going.
var wh = new ManualResetEvent(false);
//Method to Import, wraped in a delegate
WaitCallback fatherMethod = new WaitCallback(process.importProcess);
//and its parameters
processClass.importParameters param = new processClass.importParameters(wh, father.Value, null, dateSince);
// Queue the parent task.
ThreadPool.QueueUserWorkItem(fundMethod, param);
// Register the child tasks.
foreach (ListItem child in checkBoxListChild.Items)
if (child.Selected == true)
processClass.importParameters parameters = new processClass.importParameters(null, child.Value, null, dateSince);
// Registers a callback for the child task that will execute once the
// parent task is complete.
WaitOrTimerCallback childMethod = new WaitOrTimerCallback(process.anotherImportProcess);
RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(wh, childMethod, parameters, Timeout.Infinite, true);
//End if (child.Selected == true)
//End foreach (ListItem fund in checkBoxListChild.Items)
//End if (father.Selected == true)
//End foreach (ListItem fundProcess in checkBoxListFather.Items)
dateSince = dtSince.AddDays(1);
//结束 while (DateTime.Compare(since,to) 几乎相同的答案,只是使用了没有 lambda 表达式的方法并在它们上使用了参数。 我仍然没有对它进行压力测试,但它工作得很好。 谢谢布赖恩。
【问题讨论】:
【参考方案1】:如果你真的想为每个任务指定一个线程,那么根本不需要使用WaitHandle
实例。1你可以传递Thread
实例,它正在执行父级任务,到每个子任务并调用Join
以确保父任务已完成。
void TaskEntryPoint(Thread parent, ImportTask task)
if (parent != null)
parent.Join(); // Wait for the parent task to complete.
task.Execute(); // Execute the child task.
现在您需要做的就是让父任务在各自独立的线程上运行,然后让子任务在各自独立的线程上运行。调用 TaskEntryPoint
时,如果是针对父任务,则传递 null
,并为每个子任务传递适当的 Thread
实例。
更新:
根据您的评论,这里是我如何使用ThreadPool
解决问题的示例。这是使用ThreadPool.RegisterWaitForSingleObject
方法的相当高级的模式。它也恰好是一个极具可扩展性的解决方案,因为它使用绝对最少的资源来等待WaitHandle
得到信号。
foreach (ImportTask parent in parentTasks)
// This WaitHandle will be used to get the child tasks going.
var wh = new ManualResetEvent(false);
// Needed to capture the loop variable correctly.
var p = parent;
// Queue the parent task.
ThreadPool.QueueUserWorkItem(
(state) =>
try
// Execute the parent task.
p.Execute();
finally
// Signal the event so that the child tasks can begin executing.
wh.Set();
, null);
// Register the child tasks.
foreach (ImportTask child in parent.ChildTasks)
// Needed to capture the loop variable correctly.
var c = child;
// Registers a callback for the child task that will execute once the
// parent task is complete.
RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(wh,
(state, to) =>
// Execute the child task.
c.Execute();
,
null, Timeout.Infinite, true);
这里的魔力在于RegisterWaitForSingleObject
等待事件的方式。它将注册一个回调,一旦事件发出信号,该回调将自动执行。但是,它这样做的方式是不会浪费池中的线程来等待该事件。同样,这是一个相当复杂的模式,需要您进行一些思考,但它会非常可扩展。
1为每个任务启动一个新线程可能不是最佳策略。您是否考虑过使用ThreadPool
或Task
类?
【讨论】:
对不起,布莱恩。我没有具体说明,但我使用 ThreadPool 来管理线程,因为在一年左右的时间里,我可能会为这个进程创建 200 多个线程。我还能在 ThreadPool 中使用你的逻辑吗? 非常感谢您的回答。我会尝试实现它并让你知道它是如何结束的。就一个问题。我对 lambda 表达式不是很熟悉,所以 (state, to) => // 执行子任务上的“to”是什么。 c.执行(); , null, Timeout.Infinite, true); @Huggy:这是WaitOrTimerCallback
所需的参数之一。在我的示例中未使用它。当然,您不必使用 lambda 表达式。如果您愿意,可以单独定义方法。【参考方案2】:
你知道吗
-
WaitHandle.WaitAny Method
WaitHandle.WaitAll Method
如果线程本质上是简单的线性,并且您不需要排队以实现可伸缩性,您也许可以使用C#: Waiting for all threads to complete
【讨论】:
谢赫,只有一些是线性的,我确实需要排队以实现可扩展性。我检查了这两种方法,但问题是检查一些线程,以启动其他一组线程,而不是全部。以上是关于在 c# .Net 3.5 中,如何控制多个 WaitHandles?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C# 在 ASP.NET 3.5 中动态设置“application/ld+json”Schema.org 元数据
如何在 c# .net CF 3.5 中使用 XmlDocument 向 xml 添加属性
使用 .NET Framework 3.5 在 C# 中调用 Web API