C# 如何在多个线程之间通信?
我正在为另一个程序编写一个插件,它使用本机程序打开一系列文件,从中提取一些数据。我遇到的一个问题是,这个过程需要很长时间,我希望用户界面不会挂起。另外,我还想让用户能够在流程完成之前取消流程。在过去,我使用了一个后台工作人员来完成这类工作,但在这种情况下,我认为后台工作人员不起作用 要通过我使用的API创建插件,可以通过从IAPICommand接口继承来创建自定义命令。此接口包括一个执行(应用程序应用程序)方法。然后,当用户在程序中调用自定义命令时,该类被实例化,程序调用Execute()方法 调用Execute()方法时,会向其传递对当前应用程序对象的引用,正是该应用程序对象用于打开要从中提取数据的文件。但是,当原始Execute()线程以外的线程请求时,应用程序实例无法打开文档 因此,UI通常存在于主线程上,而耗时的数据提取将在辅助线程上执行。但是,在这种情况下,数据提取必须在主线程上执行,我需要为UI创建一个辅助线程 下面是代码的精简版本C# 如何在多个线程之间通信?,c#,winforms,multithreading,thread-safety,C#,Winforms,Multithreading,Thread Safety,我正在为另一个程序编写一个插件,它使用本机程序打开一系列文件,从中提取一些数据。我遇到的一个问题是,这个过程需要很长时间,我希望用户界面不会挂起。另外,我还想让用户能够在流程完成之前取消流程。在过去,我使用了一个后台工作人员来完成这类工作,但在这种情况下,我认为后台工作人员不起作用 要通过我使用的API创建插件,可以通过从IAPICommand接口继承来创建自定义命令。此接口包括一个执行(应用程序应用程序)方法。然后,当用户在程序中调用自定义命令时,该类被实例化,程序调用Execute()方法
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();
}
}
下面是一个流程图,显示了我认为这最终应该如何工作
我假设主机应用程序是WinForms应用程序 您需要在
Execute
方法中保存来自原始线程的,然后调用其Send
方法在主机的UI线程上执行代码
例如:
class MyCommand:IAPICommand
{
SynchronzationContext hostContext;
public void Execute(Application app) // method from IAPICommand
{
hostContext = SynchronzationContext.Current;
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()
SomeType someData = null;
hostContext.Send(delegate { someData = app.SomeMethod(); }, null);
}
}
在应用程序中有多个线程,每个线程都创建表单,这通常不是一个好主意。要做到这一点并非不可能,但这比你想象的要困难得多,因为处于父子关系中的表单会相互发送消息,当它们发送消息时,发送消息的表单会阻塞,直到接收消息的表单处理完为止 将此与显式执行的线程之间的消息传递或同步相结合,很容易导致死锁。因此,一般来说,最好确保为用户界面保留主线程,并在没有UI的其他线程中执行所有处理
如果符合该设计,则后台线程可以使用将消息传递给UI线程,而无需等待消息被处理。除了其他答案之外,我建议您使用ProcessWidget的回调方法将进度传递回调用线程。要提前停止工作线程,可以使用回调向工作线程返回暂停信号(如果它足够频繁地更新调用方)。或者使用单独的回调方法定期检查是否通过。或者设置一个(喘息!)全局静态标志,让工作人员定期检查。或者在工作线程上调用Thread.Abort,并让它捕获ThreadAbortException以清理任何资源 如果你看一下Java swing,它是一个很好的例子,说明了如何做到这一点: 1) 主线程负责处理所有UI请求。这将从应用程序中删除任何竞争条件 2) 任何时候任何“工作”都要完成,产生一个线程(或线程池)并完成工作。因此,除了几微秒之外,主线程不会停止,UI在发生任何事情时都会完全响应 3) 在所有语言中都必须有线程中断机制。在java中,您在线程上调用.interrupt(),当前运行的线程在执行的任何地方都会抛出InterruptedException。您的任务是捕获该异常,找出是否真的被中断(请阅读本部分的javadocs),以及是否让自己死掉(返回run方法) 1+2=不引人注目的客户互动 3=终止线程 3的替代方法(如果3太复杂)是给线程一个方法.kill();该方法设置一个kill标志。在循环中从硬盘读取缓冲区时,检查是否设置了kill标志,如果设置了kill标志,则断开循环,关闭处理程序,然后返回run方法 编辑:抱歉,忘记提及进度报告: 您的线程应该有一个公开的线程安全方法来获取“进度报告”,或者更确切地说是一个包含进度信息的数据结构。您的UI线程应该定期(比如每0.5秒)检查线程的进度报告并更新UI的