繁体   English   中英

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

[英]Application.Run(form) never returns (after using System::Management)

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

也许问题与我收到的消息有关:

60秒钟以来,CLR无法从COM上下文0x197060过渡到COM上下文0x196ef0。 拥有目标上下文/公寓的线程很可能要么执行非泵送等待,要么处理很长时间运行的操作而不泵送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!_WaitForMultipleObjectsEx8字节+0(15) dll!_RealMsgWaitForMultipleObjectsEx @ 20()+ 0xe2字节ole32.dll!CCliModalLoop :: BlockFn()+ 0x96字节
ole32.dll!_CoWaitForMultipleHandles@20()-0x51b9字节mscorwks.dll!NT5WaitRoutine()+ 0x39字节mscorwks.dll!MsgWaitHelper()+ 0x97字节mscorwks.dll!Thread :: DoAppropriateAptStateWait(5)-0x97b :: DoAppropriateWaitWorker()+ 0x104字节mscorwks.dll!Thread :: DoAppropriateWait()+ 0x40字节mscorwks.dll!CLREvent :: WaitEx()+ 0x1438a9字节
mscorwks.dll!CLREvent :: Wait()+ 0x17字节
mscorwks.dll!WKS :: GCHeap :: FinalizerThreadWait()+ 0xec字节mscorwks.dll!ReleaseRCWsInCaches()+ 0xe34fd字节
mscorwks.dll!ReleaseRCWsInCachesNoThrow()+ 0x67字节mscorwks.dll!Thread :: CleanupCOMState()+ 0x1b8f83字节mscorwks.dll!Thread :: OnThreadTerminate()+ 0x46字节mscorwks.dll!DestroyThread()+ 0x3b字节
mscorwks.dll!ThreadNative :: KickOffThread()+ 0xf2字节mscorwks.dll!Thread :: intermediateThreadProc()+ 0x46字节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();
                }

新闻:最后,我发现了产生这种行为的原因。 在实例化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;
}

谢谢。

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

尝试改为从STA线程调用Application.Run()...

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

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

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
    }
}

暂无
暂无

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

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