【问题标题】:Create thread just like if it were a separated application in C#就像在 C# 中创建一个单独的应用程序一样创建线程
【发布时间】:2010-09-09 04:49:46
【问题描述】:

我在多线程应用程序上尝试使用WebBrowser 时遇到了很多异常。 COM 组件、受保护的内存和其他我使用 WebBrowser 进行操作的任何地方的异常。我只是放弃并回到我的单线程版本,它工作正常。我会发布代码,但是当我在很多地方遇到异常时,很难定位问题的原因。因此,如果作为单线程应用程序运行良好,并且当我运行同一应用程序的多个实例时它也运行良好,那么应该有一种方法可以模拟从单个应用程序运行的多个应用程序,而不必实际制作一个单独的应用程序我将从主应用程序运行。那么,我的问题是如何让 Windows 将我的线程视为不同的实例?这应该可以消除问题,因为正如我所说,当它们是不同的实例时,我没有得到任何异常。希望我说得够清楚。

【问题讨论】:

  • 哇,退后一步,重新考虑一下您的解决方案。
  • 问题是我 am 在 STA 线程上创建 WebBrowser,即使我根本不与主线程通信,我也会不断出错。

标签: c# .net windows


【解决方案1】:

WebBrowser 是一个底层的 COM 组件,即 Internet Explorer。像许多 COM 组件一样,它需要一个“单线程单元”。您必须创建一个以使其成为组件的好客之家。基本上有两个基本要求:线程需要初始化为 STA,并且需要泵送消息循环。

这是使用 Windows 窗体提供的管道的一个:

    private void runBrowserThread(Uri url) {
        var th = new Thread(() => {
            var br = new WebBrowser();
            br.DocumentCompleted += browser_DocumentCompleted;
            br.Navigate(url);
            Application.Run();
        });
        th.SetApartmentState(ApartmentState.STA);
        th.Start();
    }

    void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
        var br = sender as WebBrowser;
        if (br.Url == e.Url) {
            Console.WriteLine("Natigated to {0}", e.Url);
            Application.ExitThread();
        }
    }

请注意,DocumentCompleted 事件会在该工作线程上引发。我任意使用该事件也使线程终止。

【讨论】:

【解决方案2】:

我认为您的问题可能与 Microsoft.NET 处理 UI 控件的方式有关。基本上,控件的任何方法都必须从创建它的线程中调用(甚至可能仅是主 UI 线程)。否则,你会得到一堆与访问相关的异常。我相信您将需要使用 InvokeRequired 属性和 Invoke 方法来调用控件,这也意味着您将必须定义一个包装您要调用的每个方法的 delgate 函数。以 WebBrowser.Url 属性为例,你可以这样写:

public delegate void SetWebAddressDelegate ( WebBrowser browser, Uri newUrl);

public void SetWebAddress ( WebBrowser browser, Uri newUrl )
{
    if (browser.InvokeRequired)
        browser.Invoke(new SetWebAddressDelegate(SetWebAddress), browser, newUrl);
    else
        browser.Url = newUrl;
}

【讨论】:

  • msdn.microsoft.com/en-us/library/ms228970.aspx 的文档可能暗示了为什么框架需要这样做。基本上,托管线程不等同于操作系统线程;它们实际上是纤维。
  • 它说仅适用于在 SQL Server 中运行的东西,而不适用于一般的 .NET 线程。即使那样,它们仍然可能是实际的操作系统线程。当然在 Winforms 上,它们是 OS 线程,您不能对 UI 控件进行跨线程修改的原因与您不能在常规 C 中进行修改的原因相同:Win32 控件并非设计为线程安全的,并且通常没有充分的理由这样做。
  • @sinde:实际上,如果您阅读文章的顶部,您会发现虽然这篇文章是针对 SQL 服务器的,但它仍然适用于任何基于主机的服务器应用程序。此外,它指的是托管线程,而不是 SQL 线程。此外,我引用的部分位于底部(查找“不要假设托管线程是 Win32 线程 - 它是光纤”),它专门指托管线程对象(甚至链接到 MSDN 文档类),并且 MS 没有仅供 SQL 服务器使用的“特殊”版本的 .NET Framework。
【解决方案3】:

听起来您可能正在跨线程共享单个 WebBrowser 实例。如果每个线程都有自己的实例,并且线程之间没有相互通信,我希望这相当于运行进程的多个实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    相关资源
    最近更新 更多