c# - 如何在多个线程之间进行通信?

标签 c# winforms multithreading thread-safety

我正在为另一个程序编写一个插件,该程序使用 native 程序打开一系列文件以从中提取一些数据。我遇到的一个问题是这个过程需要很长时间,我想防止用户界面挂起。另外,我还想让用户能够在流程完成之前取消该流程。过去,我曾为此类事情使用过后台工作程序,但在这种情况下,我认为 BackgroundWorker 不会起作用。

要通过我正在使用的 API 创建插件,可以通过从 IAPICommand 接口(interface)继承来创建自定义命令。该接口(interface)包括一个 Execute(Application app) 方法。然后实例化该类,当用户在程序中调用自定义命令时,程序将调用 Execute() 方法。

Execute() 方法在调用时会传递一个对当前 Application 对象的引用,并且正是这个应用程序对象用于打开文件以从中提取数据。但是,当原始 Execute() 线程以外的线程请求时,应用程序实例无法打开文档。

因此,通常 UI 将存在于主线程上,而耗时的数据提取将在辅助线程上执行。但是,在这种情况下,数据提取必须在主线程上执行,我需要为 UI 创建一个辅助线程。

这是代码的精简版。

class MyCommand:IAPICommand
{
    public void Execute(Application app) // method from IAPICommand
    {
        Thread threadTwo= new Thread(ShowFormMethod);
        threadTwo.Start();
    }

    public void ProcessWidget(Widget w, Application app)
    { 
        //uses an App to work some magic on C
        //app must be called from the original thread that called ExecuteCommand()
    }

    //method to open custom form on a seperatethread
    public void ShowFormMethod()
    {
      MyForm form = new MyForm();
      form.ShowDialog();  
    }
}

这是一个流程图,显示了我认为这最终应该如何运作。

alt text http://dl.dropbox.com/u/113068/SOMLibThreadingDiagram.jpg

  1. 这张图有意义吗?如果有意义的话,我是否采取了正确的方法来解决这个问题?
  2. 主线程启动 UI 线程后,我希望它等待用户选择要处理的小部件,或通过关闭表单(图中的红色数字)来结束命令。如何让主线程等待,如何触发它继续处理或在 UI 线程结束时继续到结束?我在想我可以让主线程等待 Monitor 锁。然后 UI 线程将填充要处理的 Widget 的静态列表,然后脉冲主​​线程以触发处理。当窗体关闭时,UI 线程也会对主线程发出脉冲,如果在要处理的小部件列表为空时主线程被脉冲,主线程就会知道继续执行命令。
  3. 如何让主线程将小部件处理的进度或完成情况传回 UI 线程(图中的黄色箭头)?我是否只是使用表单的 BeginInvoke() 方法来执行此操作?
  4. 如何允许 UI 线程取消小部件处理(图中的绿色箭头)?我想我可以设置一个静态 bool 标志,在处理每个小部件之前检查它吗?

最佳答案

在您的应用程序中使用多个线程来创建表单通常不是一个好主意。使这项工作并非不可能,但它比你想象的要难得多,因为处于父子关系中的表单会相互发送消息,当它们这样做时,发送消息的人会阻塞,直到另一个接收处理它。

将此与您正在显式执行的线程之间的消息传递或同步混合在一起,很容易导致死锁。因此,一般来说,最好确保为用户界面保留主线程,并在没有 UI 的其他线程中进行所有处理。

如果你符合那个设计,那么后台线程可以使用Control.BeginInvoke将消息传递给 UI 线程,而无需等待消息被处理。

关于c# - 如何在多个线程之间进行通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2137372/

相关文章:

c# - 在 DbSet 中创建预过滤层

c# - 查找带和不带连字符的单词的所有可能组合

C#,将数组作为函数参数传递

c# - 关闭表单时仍在运行的后台工作程序会发生什么情况?

android - 不同线程中的 Realm Clone RealmQuery

python - 从另一个线程调用时未执行的语句

附有调试器的 C# 代码非常慢; MemoryMappedFile 的错?

c# - 如何根据某些条件(本地报告)为 tablix 中的单元格指定文本颜色?

c# - Windows 窗体 - C# - 请求管理员权限

c - 来自/dev/{random,urandom} 的快速并行随机数生成