2010-02-21 130 views
10

我有一个Windows窗体与报表模式下的ListView。对于视图中的每个项目,我需要执行长时间运行的操作,其结果是一个数字。什么是MsgWaitForMultipleObjects的C#等价物?

我在原生win32中执行此操作的方式是为每个项目创建一个工作线程(当然,我不会创建无限数量的线程),然后在线程句柄数组上创建MsgWaitForMultipleObjects()。随着每个计算完成,线程信号和主UI线程唤醒并更新。与此同时,我们抽取消息以使UI线程保持响应。

任何人都可以提供一个如何在C#中工作的例子吗?我查看了Monitor对象,而且它看起来并不是我想要的 - 或者是在阻塞时抽取消息?

谢谢。

编辑:似乎WaitHandler.WaitAny()可能实际上泵送消息。请参阅cbrumme's treatise关于CLR中的信息抽取。

+0

你说得对,Monitor不会收集消息。 WaitHandle可能是一个更好的地方,但是我找不到一个WaitHandle方法来提取消息。 – itowlson 2010-02-21 23:45:35

+0

是的,我也看到了。这不是要求我能够等待多个对象。我会等待一个事件或其他事情......我只是不想阻止用户界面。我发现的所有样本都会“睡觉(100)”或其他东西来强制上下文切换,这非常令人伤心。 – 2010-02-21 23:47:26

+0

我想问题是,在WinForms中,消息循环并不明确。所以你不能直接做一个MsgWaitX,你需要的东西会引发一个事件。例如,将每个子任务作为BackgroundWorker运行(并忘记同步基元)。 – itowlson 2010-02-22 00:13:49

回答

2

长期运行的活动对象,我认为是您的案例中的最佳选择。主线程调用代理(活动对象的)。代理将呼叫方法转换为消息,并且此消息将进入队列。代理向调用者返回未来对象(它是对未来结果的引用)。调度员一个接一个地出队消息,并且在其他线程(工作线程)中执行你的任务。当工作线程完成任务时,它会更新未来对象的结果或调用回调方法(例如,更新UI).Dispather可以有许多工作线程同时执行更多任务。

您可以看到有关长时间运行的活动对象模式的此article(带有示例)。

+0

请提供一些信息,而不仅仅是信息的链接。 – 2010-02-22 00:06:52

+0

嗯,这真的好像很多代码来解决这样一个简单的问题。我的意思是,如果我愿意的话,我总是可以捏住我自己的COM对象。如果C#框架还不够成熟,那么我可以重新编写win32代码。虽然我不得不相信他们是一个简单的方法来做到这一点。 – 2010-02-22 18:01:29

+0

是的,你是对的。这是来自MSDN的示例: connection1.Open(); SqlCommand command1 = new SqlCommand(commandText1,connection1); IAsyncResult result1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; connection2.Open(); \t \t ... \t \t 的WaitHandle [] waitHandles = { waitHandle1,waitHandle2,waitHandle3 }; \t \t bool result = WaitHandle.WaitAll(waitHandles,60000,false); – garik 2010-02-22 20:44:48

2

你的主线程是否创建了一个管理线程。你可以使用这个BackgroundWorker。此管理器线程为ListView中的每个项目启动一个工作线程。这将允许您的用户界面在后台线程正在处理时不停地响应用户输入。

现在,问题是如何等待每个工作线程完成。不幸的是,我一直无法找到一种方法来获得System.Threading.Thread对象的线程句柄。我并不是说没有办法做到这一点;我只是没有找到一个。另一个复杂的方面是,System.Threading.Thread类是密封的,所以我们不能从它得到提供某种'处理'。

这是我用的地方ManualResetEvent

假设每个工作线程只是一个ThreadPool线程。管理BackgroundWorker为ListView中的每个项目创建一个ManualResetEvent对象。当BackgroundWorker启动每个ThreadPool线程时,将ManualResetEvent作为参数传递给QueueUserWorkItem function。然后,在每个ThreadPool线程退出之前,设置ManualResetEvent对象。

然后BackgroundWorker线程可以将所有的ManualResetEvent对象放在一个数组中,并使用WaitHandle.WaitXXX functions等待该数组。随着每个线程完成,您可以使用BackgroundWorker的事件来更新UI,或者您可以使用Control.Invoke()技术更新UI(请参阅Marc Gravell的回答here)。

希望这会有所帮助。

+0

这似乎是一个合理的方法,如果我无法弄清楚消息等待。我觉得很难相信没有一个。我会更新线程,如果我找到了一些东西。 – 2010-02-22 17:59:25

相关问题