如何在.NET中调用父线程上的函数?

我有一个.NET类库,其中包含一个类,该类具有执行一些冗长操作的方法。 当客户端调用此方法时,它应该对新线程执行冗长的操作,以避免阻塞调用者。 但是一旦方法完成,它应该在主线程上执行一些代码。 在WinForms应用程序中,我可以使用System.Windows.Forms.Control.Invoke方法,但这不是我的情况。 那么我怎样才能在C#中实现这一目标?

您可以使用System.Windows.Threading.Dispatcher对象(来自WindowsBase程序集)在特定线程上调用函数。

例如:

 public class ClassCreatedBySomeThread { Dispatcher dispatcher = Dispatcher.CurrentDispatcher; public void SafelyCallMeFromAnyThread(Action a) { dispatcher.Invoke(a); } } 

如果一个线程必须能够执行另一个线程发布给它的一些代码(通常以委托的forms),它必须基本上等待那些指令。 你的主线程还在做什么? 构建一个等效的事件循环并不难(基本上你有一个代理的生产者/消费者队列),但你需要知道你不能只是打断主线程并说“现在就这样做”。

为什么必须在主线程上执行?

我找到了一个解决问题的简单方法:

我的COM对象声明如下:

 public class Runner { public void Run(string executable, object processExitHandler) { ThreadPool.QueueUserWorkItem(state => { var p = new Process() { StartInfo = new ProcessStartInfo() { FileName = executable } }; p.Start(); while (!p.HasExited) { Thread.Sleep(100); } state .GetType() .InvokeMember( "call", BindingFlags.InvokeMethod, null, state, new object[] { null, p.ExitCode } ); }, processExitHandler); } } 

在我的HTML页面中,我使用它如下:

   ActiveXRunner    Run notepad and show exit code when finished   

没有办法明确地让代码在特定的线程上运行(除了用于创建UI控件的线程 – 这是一个例外)但是如果你只是想在线程完成时调用除代码之外的代码,你可以使用与会代表。
首先声明一个委托,其中包含您要在新线程上运行的方法的签名…

 public delegate bool CheckPrimeDelegate(long n); 

然后在你的代码中,创建一个委托实例,使用BeginInvoke调用它(传递它需要的任何参数)并通过一个回调函数委托(OnChkPrimeDone)

 class MyClassApp { static void Main() { CheckPrimeDelegate ckPrimDel = new CheckPrimeDelegate(Prime.Check); // Initiate the operation ckPrimDel.BeginInvoke(4501232117, new AsyncCallback(OnChkPrimeDone), null); // go do something else . . . . } static void OnChkPrimeDone( IAsyncResult iAr) { AsyncResult ar = iAr as AsynchResult; CheckPrimeDelegate ckPrimDel = ar.AsyncDelegate as CheckPrimeDelegate; bool isPrime = ckPrimDel.EndInvoke(ar); Console.WriteLine(" Number is " + (isPrime? "prime ": "not prime"); } } 

完成后,它将调用回调函数(OnChkPrimeDone)

如果您明确需要在用于创建COM Active-X对象的线程上运行此回调函数,请检查.Net托管代码包装变量,该变量包含对此对象的引用…如果它有一个名为InvokeRequired的方法(),然后,在您的回调函数中,测试此方法的布尔返回值。
如果它具有InvokeRequired()方法并且它返回true,则active-X对象还将公开“BeginInvoke()”方法。 然后,创建另一个委托,填充相同的函数,并在Active-X对象上调用BeginInvoke,传递给它新的委托……然后它将在用于创建Active-X对象的同一个线程上运行

 If (MyActiveXObject.InvokeRequired()) MyActiveXObject.BeginInvoke(...); 

线程不能只在另一个线程上执行东西。 你可以得到的最接近的是将一个委托放在一个队列上,以便执行另一个线程,但这假定另一个线程正在合作。

在WinForms应用程序中,主循环在每次循环迭代中查找此类排队消息。

如果您只需要传达工作线程的完成,您可以使用例如标志变量。 如果主线程应该能够等待作业终止,请使用信号量或条件变量(监视器)。

这是我的确切场景:我有一个.NET类库作为COM对象公开(使用regasm.exe)。 COM对象包含一个运行外部应用程序的方法(使用Process.Start)。 COM对象用于Internet Explorer。 所以我的网页运行外部应用程序,我需要找到一种方法将ExitCode传递给网页。

起初我没有在新线程上启动外部应用程序,只是等待用户关闭应用程序,然后我的函数将ExitCode返回给调用者。 但是,当应用程序运行时,IE没有响应。 所以我决定在新线程中启动应用程序,但现在我不能再返回ExitCode了。

COM对象是使用: new ActiveXObject指令创建的,遗憾的是javascript不支持事件下沉,因此我无法在应用程序退出时触发的C#中编写事件。