繁体   English   中英

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

[英]How to invoke a function on parent thread in .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);
    }
} 

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

我的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页面中,我使用它:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head><title>ActiveXRunner</title>    
    <script type="text/javascript">
    function runNotepad() {
        var ax = new ActiveXObject('ActiveXRunner.Runner');
        ax.Run('c:\\windows\\notepad.exe', h);
    }

    function h(exitCode) {
        alert('exitCode = ' + exitCode);
    }
    </script>
</head>
<body>
    <a href="#" onclick="runNotepad();">Run notepad and show exit code when finished</a>
</body>
</html>

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

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

没有办法明确地让代码在特定的线程上运行(除了用于创建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#中编写事件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM