Application.Run(form)永远不会返回(在使用System :: Management之后)

时间:2010-12-02 09:46:55

标签: c# .net c++ visual-c++

我有一个类库程序集,一旦加载就打开一个表单(form1),当提示时,form1打开其他表单(form2)。每个表单都在一个单独的线程中运行,这是因为在每个表单中运行flashweave应用程序,并且为了性能,我需要在单独的theads中运行它们。 如果我使用用c#编写的托管加载程序加载库,一切正常。 如果我使用混合的clr / c ++程序集加载库,当form2关闭时,Application.Run()不会返回导致许多卡住的线程。 我也尝试使用Thread.Abort()强制中止线程,但线程仍然没有中止。 如果我关闭form1 application.run()返回,它的线程可以停止。 我还尝试打开简单的空表单而不是form2而没有任何flashwave对象,但它仍然没有返回。

也许问题与我得到的这条消息有关:

  

CLR无法过渡   从COM上下文0x197060到COM   上下文0x196ef0持续60秒。该   拥有目的地的线程   上下文/公寓是最有可能的   或者做一次非抽水等待或者   处理很长时间   没有泵Windows的操作   消息。这种情况一般都有   负面的业绩影响和可能   甚至导致应用程序成为   无响应或内存使用   随着时间的推移不断积累。至   一切都避免这个问题   线程公寓(STA)线程   应该使用抽等待原语   (例如CoWaitForMultipleHandles)和   经常在长时间内发送消息   正在运行。

关于form2开放:

private void OpenTable()
{
            if (!this.InvokeRequired)
            {

                Thread TableRun = new Thread(new ThreadStart(OpenTable));
                TableRun.ApartmentState = ApartmentState.STA;
                TableRun.IsBackground = false;
                TableRun.Name = "T2"; 
                TableRun.Start();

                return;
            }
            try
            {
                FormTable T = new FormTable(;
                T.MyThread = Thread.CurrentThread;
                Application.Run(T);
            }
            catch (Exception ex)
            {

            }
}

卡住线程的堆栈跟踪:

  

ntdll.dll!_ZwWaitForMultipleObjects@20()   + 0x15字节ntdll.dll!_ZwWaitForMultipleObjects@20()   + 0x15字节KernelBase.dll!_WaitForMultipleObjectsEx@20()   + 0x36字节kernel32.dll!_WaitForMultipleObjectsExImplementation@20()   + 0x8e byte user32.dll!_RealMsgWaitForMultipleObjectsEx@20()   + 0xe2 byte ole32.dll!CCliModalLoop :: BlockFn()+   0x96字节
    ole32.dll!_CoWaitForMultipleHandles@20()    - 0x51b9 byte mscorwks.dll!NT5WaitRoutine()+ 0x39   byte mscorwks.dll!MsgWaitHelper()   + 0x97 byte mscorwks.dll!Thread :: DoAppropriateAptStateWait()    - 0xf32e5 byte mscorwks.dll!Thread :: DoAppropriateWaitWorker()   + 0x104 byte mscorwks.dll!Thread :: DoAppropriateWait()   + 0x40 byte mscorwks.dll!CLREvent :: WaitEx()+   0x1438a9字节
    mscorwks.dll!CLREvent :: Wait()+ 0x17   字节
    的Mscorwks.dll!WKS :: GCHeap :: FinalizerThreadWait()   + 0xec byte mscorwks.dll!ReleaseRCWsInCaches()+   0xe34fd字节
    的Mscorwks.dll!ReleaseRCWsInCachesNoThrow()   + 0x67 byte mscorwks.dll!Thread :: CleanupCOMState()   + 0x1b8f83 byte mscorwks.dll!Thread :: OnThreadTerminate()   + 0x46字节mscorwks.dll!DestroyThread()+ 0x3b   字节
    的Mscorwks.dll!ThreadNative :: KickOffThread()   + 0xf2 byte mscorwks.dll!Thread :: intermediateThreadProc()   + 0x46 byte kernel32.dll!@ BaseThreadInitThunk @ 12()   + 0x12字节

关于显示第一个帖子的代码是:

//c++ code
        Assembly::form^ f= gcnew Assembly::form() ; 
        f->Load();
        gcroot<Assembly::form^>* dsa3_gc_p= new gcroot<Assembly::form^>(f);
        this->obMainLib = (void *)dsa3_gc_p;
//------------------------
//The c++ loader just calls the Load() method
//c#library   
        public void Load()
                {
                    FormThread = new Thread(new ThreadStart(this.Start));
                    FormThread.Name = "T7";
                    FormThread.IsBackground = true;
                    FormThread.SetApartmentState(ApartmentState.STA);
                    FormThread.Start();    
                }
        private void Start()
                {
                    Config = GlobalConfig.GetConfig(GlobalConfig.ConfigurationFile);
                    HttpInterface = new DHttpInterface(Config);
                    Lobby = new FormLobby(HttpInterface, false);


                    WorkerThread = new Thread(new ThreadStart(this.Start));
                    WorkerThread.Name = "T6";
                    WorkerThread.IsBackground = true;
                    WorkerThread.ApartmentState = ApartmentState.STA;
                    WorkerThread.Start();

                    Application.Run(Lobby);
                    Config.SaveToDisk();
                }

NEWS: 最后我发现了什么产生了这种行为。在实例化c#库之前,加载器尝试使用.net System :: Management来获取cpu序列,如果我删除这样的部分,那么一切正常。 这是有罪的部分:

std::string Loader::GetCPUID()
{
    std::string lsCPUID = "";
    try
    {
        System::Management::ManagementObjectCollection^ moReturn  = nullptr;
        System::Management::ManagementObjectSearcher^ moSearch  ;

        moSearch = gcnew System::Management::ManagementObjectSearcher("Select * from Win32_Processor");

        moReturn = moSearch->Get();
        for each ( System::Management::ManagementObject^ mo in moReturn )
        {
            char * chp = (char *) System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(mo["ProcessorID"]->ToString()).ToPointer();
            lsCPUID.assign(chp);
        }
    }
    catch(System::Exception^ ex )
    {
    }

    return lsCPUID;
}

感谢。

2 个答案:

答案 0 :(得分:0)

是否有可能从MTA线程调用OpenTable,InvokeRequired返回true,因此它不是创建另一个STA线程,而是直接在MTA线程上调用Application.Run()?

尝试从STA线程调用Application.Run()而不是......

答案 1 :(得分:0)

我终于找到了方法。我创建了一个新的AppDomain,我运行该方法来获取cpu序列,然后卸载该域,以便导致问题的System :: Management库被卸载。

ref class MarshalByRefType:MarshalByRefObject { 上市:     //通过代理调用此方法。

std::string GetCPUID()
{
    //char * chp = (char *) System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(R671::R671::Value()).ToPointer();
    std::string lsCPUID = "";
    //return lsCPUID.assign(chp);
    try
    {
        System::Management::ManagementObjectCollection^ moReturn  = nullptr;
        System::Management::ManagementObjectSearcher^ moSearch  ;

        moSearch = gcnew System::Management::ManagementObjectSearcher("Select * from Win32_Processor");

        moReturn = moSearch->Get();
        for each ( System::Management::ManagementObject^ mo in moReturn )
        {
            char * chp = (char *) System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(mo["ProcessorID"]->ToString()).ToPointer();
            lsCPUID.assign(chp);
        }
    }
    catch(System::Exception^ ex )
    {
    }
    AppDomainSetup^ ads = AppDomain::CurrentDomain->SetupInformation;
    String^ str = String::Format("AppName={0}, AppBase={1}, ConfigFile={2}", 
        ads->ApplicationName, 
        ads->ApplicationBase, 
        ads->ConfigurationFile);

    char * chp = (char *) System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str).ToPointer();
    lsCPUID.assign(chp);
    return lsCPUID;
}

}

class Loader
{
  std::string  GetCPUID()
    {
        String^ callingDomainName = Thread::GetDomain()->FriendlyName;

        // Construct and initialize settings for a second AppDomain.
        AppDomainSetup^ ads = gcnew AppDomainSetup();
        ads->ApplicationBase = 
            "file:///" +  Assembly::GetExecutingAssembly()->Location;
        ads->DisallowBindingRedirects = false;
        ads->DisallowCodeDownload = true;
        ads->ConfigurationFile = 
            AppDomain::CurrentDomain->SetupInformation->ConfigurationFile;

        // Create the second AppDomain.
        AppDomain^ ad2 = AppDomain::CreateDomain("AD #2", 
            AppDomain::CurrentDomain->Evidence, ads);
        String^ sam = R671::R671::typeid->FullName;
        // Create an instance of MarshalbyRefType in the second AppDomain. 
        // A proxy to the object is returned.
        MarshalByRefType^ mbrt = 
            (MarshalByRefType^) ad2->CreateInstanceFromAndUnwrap(
            Assembly::GetExecutingAssembly()->Location, 
                MarshalByRefType::typeid->FullName
            );
        string lsCPUID;
        //char * chp = (char *) System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(mbrt2->Value()).ToPointer();
        lsCPUID = mbrt->GetCPUID();
        try
        {
            AppDomain::Unload(ad2);
        }   
        catch ( AppDomainUnloadedException^ /*e*/ ) 
        {

        }

        return lsCPUID;
    }

    void Load()
    {
        //do things
        std:string cpuid = this->GetCPUID();
        //do things
        //load c# library and open forms
    }
}