Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建线程就像在C中创建一个独立的应用程序一样#_C#_.net_Windows - Fatal编程技术网

C# 创建线程就像在C中创建一个独立的应用程序一样#

C# 创建线程就像在C中创建一个独立的应用程序一样#,c#,.net,windows,C#,.net,Windows,在尝试在多线程应用程序上使用时,我遇到了一系列异常。COM组件、受保护的内存和其他异常,我在使用WebBrowser时到处都会遇到。我只是放弃了,回到了我的单线程版本,它工作得很好。我会发布代码,但当我在这么多地方遇到异常时,很难定位问题的原因。因此,如果作为一个单线程应用程序,它可以正常运行,如果我运行同一应用程序的多个实例时,它也可以正常运行,那么应该有一种方法来模拟从单个应用程序运行的多个应用程序,而不必实际创建一个从主应用程序运行的独立应用程序。那么,我的问题是,如何让Windows将线

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

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

我认为您的问题可能与Microsoft.NET处理UI控件的方式有关。基本上,控件的任何方法都必须从创建它的线程(甚至可能是主UI线程)调用。否则,将出现一系列与访问相关的异常。我相信您将需要使用invokererequired属性和Invoke方法来调用控件,这也意味着您必须定义一个delgate函数来封装您想要调用的每个方法。以WebBroweser.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;
}

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事件在该工作线程上引发。我任意使用该事件也使线程终止。

哇,退后一步,重新考虑您的解决方案。问题是,我正在STA线程上创建WebBrowser,即使我根本不与主线程通信,我也会不断出错。中的文档可能会暗示框架为什么需要这样做。基本上,托管线程并不等同于操作系统线程;它们实际上是光纤。它说,这只适用于在SQL Server中运行的东西,而不适用于一般的.NET线程。即便如此,它们仍然可能是真正的操作系统线程。当然,在Winforms上,它们是操作系统线程,不能对UI控件进行跨线程修改的原因与不能在常规C中进行跨线程修改的原因相同:Win32控件不是为线程安全而设计的,通常也没有很好的理由让它们这样做。@sinde:事实上,如果你读了文章的顶部,它说,尽管本文面向SQL server,但它仍然适用于任何基于主机的服务器应用程序。此外,它指的是托管线程,而不是SQL线程。此外,我引用的部分位于底部(查找“不要假设托管线程是Win32线程–它是一个光纤”),它专门指托管线程对象(甚至指向该类的MSDN文档的链接),MS没有“特殊的”仅供SQL server使用的.NET Framework版本。我不明白您为什么在那里调用
Application.Run()
?确切地说,什么是泵送消息循环?Application.Run()泵送消息循环。链接: