久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

<i id='ToigK'><tr id='ToigK'><dt id='ToigK'><q id='ToigK'><span id='ToigK'><b id='ToigK'><form id='ToigK'><ins id='ToigK'></ins><ul id='ToigK'></ul><sub id='ToigK'></sub></form><legend id='ToigK'></legend><bdo id='ToigK'><pre id='ToigK'><center id='ToigK'></center></pre></bdo></b><th id='ToigK'></th></span></q></dt></tr></i><div class="qwawimqqmiuu" id='ToigK'><tfoot id='ToigK'></tfoot><dl id='ToigK'><fieldset id='ToigK'></fieldset></dl></div>

    <tfoot id='ToigK'></tfoot><legend id='ToigK'><style id='ToigK'><dir id='ToigK'><q id='ToigK'></q></dir></style></legend>

      • <bdo id='ToigK'></bdo><ul id='ToigK'></ul>

        <small id='ToigK'></small><noframes id='ToigK'>

        為什么在 Win32 控制臺(tái)應(yīng)用程序啟動(dòng)時(shí)會(huì)出現(xiàn)三個(gè)

        Why there are three unexpected worker threads when a Win32 console application starts up?(為什么在 Win32 控制臺(tái)應(yīng)用程序啟動(dòng)時(shí)會(huì)出現(xiàn)三個(gè)意外的工作線程?)

        <small id='8pJY1'></small><noframes id='8pJY1'>

              <tbody id='8pJY1'></tbody>

              1. <i id='8pJY1'><tr id='8pJY1'><dt id='8pJY1'><q id='8pJY1'><span id='8pJY1'><b id='8pJY1'><form id='8pJY1'><ins id='8pJY1'></ins><ul id='8pJY1'></ul><sub id='8pJY1'></sub></form><legend id='8pJY1'></legend><bdo id='8pJY1'><pre id='8pJY1'><center id='8pJY1'></center></pre></bdo></b><th id='8pJY1'></th></span></q></dt></tr></i><div class="qwawimqqmiuu" id='8pJY1'><tfoot id='8pJY1'></tfoot><dl id='8pJY1'><fieldset id='8pJY1'></fieldset></dl></div>
              2. <legend id='8pJY1'><style id='8pJY1'><dir id='8pJY1'><q id='8pJY1'></q></dir></style></legend>
                  <bdo id='8pJY1'></bdo><ul id='8pJY1'></ul>
                  <tfoot id='8pJY1'></tfoot>
                • 本文介紹了為什么在 Win32 控制臺(tái)應(yīng)用程序啟動(dòng)時(shí)會(huì)出現(xiàn)三個(gè)意外的工作線程?的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!

                  問(wèn)題描述

                  這是情況的截圖!

                  我使用 VS2010 創(chuàng)建了一個(gè) Visual C++ Win32 控制臺(tái)應(yīng)用程序.當(dāng)我啟動(dòng)應(yīng)用程序時(shí),我發(fā)現(xiàn)有四個(gè)線程:一個(gè)主線程"和三個(gè)工作線程(我沒(méi)有寫(xiě)任何代碼).

                  I created a Visual C++ Win32 Console Application with VS2010. When I started the application, I found that there were four threads: one 'Main Thread' and three worker threads (I didn't write any code).

                  我不知道這三個(gè)工作線程從何而來(lái).
                  我想知道這三個(gè)線程的作用.

                  I don't know where these three worker threads came from.
                  I would like to know the role of these three threads.

                  提前致謝!

                  推薦答案

                  Windows 10 實(shí)現(xiàn)了一種新的 DLL 加載方式 - 多個(gè)工作線程并行執(zhí)行 (LdrpWorkCallback).所有 Windows 10 進(jìn)程現(xiàn)在都有幾個(gè)這樣的線程.

                  Windows 10 implemented a new way of loading DLLs - several worker threads do it in parallel (LdrpWorkCallback). All Windows 10 processes now have several such threads.

                  在 Win10 之前,系統(tǒng) (ntdll.dll) 總是在單個(gè)線程中加載 DLL,但從 Win10 開(kāi)始,這種行為發(fā)生了變化.現(xiàn)在是并行加載器"存在于 ntdll 中.現(xiàn)在加載任務(wù)(NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext))可以在工作線程中執(zhí)行.幾乎每個(gè) DLL 都有導(dǎo)入(依賴 DLL),所以當(dāng)一個(gè) DLL 被加載時(shí) - 它的依賴 DLL 也被加載并且這個(gè)過(guò)程是遞歸的(依賴 DLL 有自己的依賴).

                  Before Win10, the system (ntdll.dll) always loaded DLLs in a single thread, but starting with Win10 this behaviour changed. Now a "Parallel loader" exists in ntdll. Now the loading task (NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext)) can be executed in worker threads. Almost every DLL has imports (dependent DLLs), so when a DLL is loaded - its dependent DLLs are also loaded and this process is recursive (dependent DLLs have own dependencies).

                  函數(shù) void LdrpMapAndSnapDependency(LDRP_LOAD_CONTEXT* LoadContext) 遍歷當(dāng)前加載的 DLL 導(dǎo)入表,并通過(guò)調(diào)用 LdrpLoadDependentModule()(其中為新加載的 DLL 在內(nèi)部調(diào)用 LdrpMapAndSnapDependency() - 所以這個(gè)過(guò)程是遞歸的).最后,LdrpMapAndSnapDependency() 需要調(diào)用 NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext) 將導(dǎo)入綁定到已加載的 DLL.LdrpSnapModule() 在頂級(jí) DLL 加載過(guò)程中為許多 DLL 執(zhí)行,并且該過(guò)程對(duì)于每個(gè) DLL 都是獨(dú)立的 - 因此這是并行化的好地方.LdrpSnapModule() 在大多數(shù)情況下不會(huì)加載新的 DLL,而只會(huì)將導(dǎo)入綁定到已加載的導(dǎo)出.但是,如果導(dǎo)入被解析為轉(zhuǎn)發(fā)導(dǎo)出(這種情況很少發(fā)生) - 會(huì)加載新的轉(zhuǎn)發(fā) DLL.

                  The function void LdrpMapAndSnapDependency(LDRP_LOAD_CONTEXT* LoadContext) walks the current loaded DLL import table and loads its direct (1st level) dependent DLLs by calling LdrpLoadDependentModule() (which internally calls LdrpMapAndSnapDependency() for the newly loaded DLL - so this process is recursive). Finally, LdrpMapAndSnapDependency() needs to call NTSTATUS LdrpSnapModule(LDRP_LOAD_CONTEXT* LoadContext) to bind imports to the already loaded DLLs. LdrpSnapModule() is executed for many DLLs in the top level DLL load process, and this process is independent for every DLL - so this is a good place to parallelize. LdrpSnapModule() in most cases does not load new DLLs, but only binds import to export from already loaded ones. But if an import is resolved to a forwarded export (which rarely happens) - the new, forwarded DLL, is loaded.

                  一些當(dāng)前的實(shí)施細(xì)節(jié):

                  1. 首先,讓我們看看 struct _RTL_USER_PROCESS_PARAMETERS 新字段 - ULONG LoaderThreads.這個(gè) LoaderThreads(如果設(shè)置為非零)啟用或禁用并行加載器"在新的過(guò)程中.當(dāng)我們通過(guò) ZwCreateUserProcess() 創(chuàng)建新進(jìn)程時(shí)- 第 9 個(gè)參數(shù)是PRTL_USER_PROCESS_PARAMETERS 過(guò)程參數(shù).但是如果我們使用 CreateProcess[Internal]W() - 我們不能直接傳遞 PRTL_USER_PROCESS_PARAMETERS - 只有 STARTUPINFO.RTL_USER_PROCESS_PARAMETERS 是從STARTUPINFO 部分初始化的,但是我們不控制ULONG LoaderThreads,它永遠(yuǎn)為零(如果我們不調(diào)用ZwCreateUserProcess() 或?yàn)榇死淘O(shè)置一個(gè)鉤子).

                  1. first of all, let us look into the struct _RTL_USER_PROCESS_PARAMETERS new field - ULONG LoaderThreads. this LoaderThreads (if set to nonzero) enables or disables "Parallel loader" in the new process. When we create a new process by ZwCreateUserProcess() - the 9th argument is PRTL_USER_PROCESS_PARAMETERS ProcessParameters. but if we use CreateProcess[Internal]W() - we cannot pass PRTL_USER_PROCESS_PARAMETERS directly - only STARTUPINFO. RTL_USER_PROCESS_PARAMETERS is partially initialized from STARTUPINFO, but we do not control ULONG LoaderThreads, and it will always be zero (if we do not call ZwCreateUserProcess() or set a hook to this routine).

                  在新的進(jìn)程初始化階段,調(diào)用LdrpInitializeExecutionOptions()(來(lái)自LdrpInitializeProcess()).此例程檢查 HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options 的幾個(gè)值(如果 子鍵存在 - 通常不存在),包括 MaxLoaderThreads (REG_DWORD) - 如果 MaxLoaderThreads 存在 - 它的值覆蓋RTL_USER_PROCESS_PARAMETERS.LoaderThreads.

                  In the new process initialization phase, LdrpInitializeExecutionOptions() is called (from LdrpInitializeProcess()). This routine checks HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options<app name> for several values (if the <app name> subkey exists - usually it doesn't), including MaxLoaderThreads (REG_DWORD) - if MaxLoaderThreads exists - its value overrides RTL_USER_PROCESS_PARAMETERS.LoaderThreads.

                  LdrpCreateLoaderEvents() 被調(diào)用.此例程必須創(chuàng)建 2 個(gè)全局事件:HANDLE LdrpWorkCompleteEvent, LdrpLoadCompleteEvent;,用于同步.

                  LdrpCreateLoaderEvents() is called. This routine must create 2 global events: HANDLE LdrpWorkCompleteEvent, LdrpLoadCompleteEvent;, which are used for synchronization.

                  NTSTATUS LdrpCreateLoaderEvents()
                  {
                      NTSTATUS status = ZwCreateEvent(&LdrpWorkCompleteEvent, EVENT_ALL_ACCESS, 0, SynchronizationEvent, TRUE);
                  
                      if (0 <= status)
                      {
                          status = ZwCreateEvent(&LdrpLoadCompleteEvent, EVENT_ALL_ACCESS, 0, SynchronizationEvent, TRUE);
                      }
                      return status;
                  }
                  

                • LdrpInitializeProcess() 調(diào)用 void LdrpDetectDetour().這個(gè)名字不言自明.它不返回值而是初始化全局變量BOOLEAN LdrpDetourExist.這個(gè)例程首先檢查一些加載器關(guān)鍵例程是否被鉤住 - 目前有 5 個(gè)例程:

                • LdrpInitializeProcess() calls void LdrpDetectDetour(). This name speaks for itself. it does not return a value but initializes the global variable BOOLEAN LdrpDetourExist. This routine first checks whether some loader critical routines are hooked - currently these are 5 routines:

                  • NtOpenFile
                  • NtCreateSection
                  • NtQueryAttributesFile
                  • NtOpenSection
                  • NtMapViewOfSection

                  如果是 - LdrpDetourExist = TRUE;

                  如果沒(méi)有鉤住 - ThreadDynamicCodePolicyInfo 被查詢 - 完整代碼:

                  If not hooked - ThreadDynamicCodePolicyInfo is queried - full code:

                  void LdrpDetectDetour()
                  {
                      if (LdrpDetourExist) return ;
                  
                      static PVOID LdrpCriticalLoaderFunctions[] = {
                          NtOpenFile,
                          NtCreateSection,
                          ZwQueryAttributesFile,
                          ZwOpenSection,
                          ZwMapViewOfSection,
                      };
                  
                      static M128A LdrpThunkSignature[5] = {
                          //***
                      };
                  
                      ULONG n = RTL_NUMBER_OF(LdrpCriticalLoaderFunctions);
                      M128A* ppv = (M128A*)LdrpCriticalLoaderFunctions;
                      M128A* pps = LdrpThunkSignature; 
                      do
                      {
                          if (ppv->Low != pps->Low || ppv->High != pps->High)
                          {
                              if (LdrpDebugFlags & 5)
                              {
                                  DbgPrint("!!! Detour detected, disable parallel loading
                  ");
                                  LdrpDetourExist = TRUE;
                                  return;
                              }
                          }
                  
                      } while (pps++, ppv++, --n);
                  
                      BOOL DynamicCodePolicy;
                  
                      if (0 <= ZwQueryInformationThread(NtCurrentThread(), ThreadDynamicCodePolicyInfo, &DynamicCodePolicy, sizeof(DynamicCodePolicy), 0))
                      {
                          if (LdrpDetourExist = (DynamicCodePolicy == 1))
                          {
                              if (LdrpMapAndSnapWork)
                              {
                                  WaitForThreadpoolWorkCallbacks(LdrpMapAndSnapWork, TRUE);//TpWaitForWork
                                  TpReleaseWork(LdrpMapAndSnapWork);//CloseThreadpoolWork
                                  LdrpMapAndSnapWork = 0;
                                  TpReleasePool(LdrpThreadPool);//CloseThreadpool
                                  LdrpThreadPool = 0;
                              }
                          }
                      }
                  }
                  

                • LdrpInitializeProcess() 調(diào)用 NTSTATUS LdrpEnableParallelLoading (ULONG LoaderThreads) - 作為 LdrpEnableParallelLoading(ProcessParameters->LoaderThreads):>

                • LdrpInitializeProcess() calls NTSTATUS LdrpEnableParallelLoading (ULONG LoaderThreads) - as LdrpEnableParallelLoading(ProcessParameters->LoaderThreads):

                  NTSTATUS LdrpEnableParallelLoading (ULONG LoaderThreads)
                  {
                      LdrpDetectDetour();
                  
                      if (LoaderThreads)
                      {
                          LoaderThreads = min(LoaderThreads, 16);// not more than 16 threads allowed
                          if (LoaderThreads <= 1) return STATUS_SUCCESS;
                      }
                      else
                      {
                          if (RtlGetSuiteMask() & 0x10000) return STATUS_SUCCESS; 
                          LoaderThreads = 4;// default for 4 threads
                      }
                  
                      if (LdrpDetourExist) return STATUS_SUCCESS;
                  
                      NTSTATUS status = TpAllocPool(&LdrpThreadPool, 1);//CreateThreadpool
                  
                      if (0 <= status)
                      {
                          TpSetPoolWorkerThreadIdleTimeout(LdrpThreadPool, -300000000);// 30 second idle timeout
                          TpSetPoolMaxThreads(LdrpThreadPool, LoaderThreads - 1);//SetThreadpoolThreadMaximum 
                          TP_CALLBACK_ENVIRON CallbackEnviron = { };
                          CallbackEnviron->CallbackPriority = TP_CALLBACK_PRIORITY_NORMAL;
                          CallbackEnviron->Size = sizeof(TP_CALLBACK_ENVIRON);
                          CallbackEnviron->Pool = LdrpThreadPool;
                          CallbackEnviron->Version = 3;
                  
                          status = TpAllocWork(&LdrpMapAndSnapWork, LdrpWorkCallback, 0, &CallbackEnviron);//CreateThreadpoolWork
                      }
                  
                      return status;
                  }
                  

                  創(chuàng)建了一個(gè)特殊的加載器線程池 - LdrpThreadPool,具有 LoaderThreads - 1 個(gè)最大線程.空閑超時(shí)設(shè)置為30秒(之后線程退出)并分配PTP_WORK LdrpMapAndSnapWork,然后在void LdrpQueueWork(LDRP_LOAD_CONTEXT* LoadContext)中使用.

                  A special loader thread pool is created - LdrpThreadPool, with LoaderThreads - 1 max threads. Idle timeout is set to 30 seconds (after which the thread exits) and allocated PTP_WORK LdrpMapAndSnapWork, which is then used in void LdrpQueueWork(LDRP_LOAD_CONTEXT* LoadContext).

                  并行加載器使用的全局變量:

                  Global variables used by the parallel loader:

                  HANDLE LdrpWorkCompleteEvent, LdrpLoadCompleteEvent;
                  CRITICAL_SECTION LdrpWorkQueueLock;
                  LIST_ENTRY LdrpWorkQueue = { &LdrpWorkQueue, &LdrpWorkQueue };
                  
                  
                  ULONG LdrpWorkInProgress;
                  BOOLEAN LdrpDetourExist;
                  PTP_POOL LdrpThreadPool;
                  
                  PTP_WORK LdrpMapAndSnapWork;
                  
                  enum DRAIN_TASK {
                      WaitLoadComplete, WaitWorkComplete
                  };
                  
                  struct LDRP_LOAD_CONTEXT
                  {
                      UNICODE_STRING BaseDllName;
                      PVOID somestruct;
                      ULONG Flags;//some unknown flags
                      NTSTATUS* pstatus; //final status of load
                      _LDR_DATA_TABLE_ENTRY* ParentEntry; // of 'parent' loading dll
                      _LDR_DATA_TABLE_ENTRY* Entry; // this == Entry->LoadContext
                      LIST_ENTRY WorkQueueListEntry;
                      _LDR_DATA_TABLE_ENTRY* ReplacedEntry;
                      _LDR_DATA_TABLE_ENTRY** pvImports;// in same ordef as in IMAGE_IMPORT_DESCRIPTOR piid
                      ULONG ImportDllCount;// count of pvImports
                      LONG TaskCount;
                      PVOID pvIAT;
                      ULONG SizeOfIAT;
                      ULONG CurrentDll; // 0 <= CurrentDll < ImportDllCount
                      PIMAGE_IMPORT_DESCRIPTOR piid;
                      ULONG OriginalIATProtect;
                      PVOID GuardCFCheckFunctionPointer;
                      PVOID* pGuardCFCheckFunctionPointer;
                  };
                  

                  不幸的是 LDRP_LOAD_CONTEXT 未包含在已發(fā)布的 .pdb 文件中,因此我的定義僅包含部分名稱.

                  Unfortunately LDRP_LOAD_CONTEXT is not contained in published .pdb files, so my definitions include only partial names.

                  struct {
                      ULONG MaxWorkInProgress;//4 - values from explorer.exe at some moment
                      ULONG InLoaderWorker;//7a (this mean LdrpSnapModule called from worker thread)
                      ULONG InLoadOwner;//87 (LdrpSnapModule called direct, in same thread as `LdrpMapAndSnapDependency`)
                  } LdrpStatistics;
                  
                  // for statistics
                  void LdrpUpdateStatistics()
                  {
                    LdrpStatistics.MaxWorkInProgress = max(LdrpStatistics.MaxWorkInProgress, LdrpWorkInProgress);
                    NtCurrentTeb()->LoaderWorker ? LdrpStatistics.InLoaderWorker++ : LdrpStatistics.InLoadOwner++
                  }
                  

                  TEB.CrossTebFlags - 現(xiàn)在存在 2 個(gè)新標(biāo)志:

                  In TEB.CrossTebFlags - now exist 2 new flags:

                  USHORT LoadOwner : 01; // 0x1000;
                  USHORT LoaderWorker : 01; // 0x2000;
                  

                  最后 2 位是空閑的 (USHORT SpareSameTebBits : 02;//0xc000)

                  Last 2 bits is spare (USHORT SpareSameTebBits : 02; // 0xc000)

                  LdrpMapAndSnapDependency(LDRP_LOAD_CONTEXT* LoadContext) 包括以下代碼:

                  LDR_DATA_TABLE_ENTRY* Entry = LoadContext->CurEntry;
                  if (LoadContext->pvIAT)
                  {
                      Entry->DdagNode->State = LdrModulesSnapping;
                      if (LoadContext->PrevEntry)// if recursive call
                      {
                          LdrpQueueWork(LoadContext); // !!!
                      }
                      else
                      {
                          status = LdrpSnapModule(LoadContext);
                      }
                  }
                  else
                  {
                      Entry->DdagNode->State = LdrModulesSnapped;
                  }
                  

                  所以,如果 LoadContext->PrevEntry(假設(shè)我們加載 user32.dll.在第一次調(diào)用 LdrpMapAndSnapDependency() 時(shí),LoadContext->PrevEntry 將始終為 0(當(dāng) CurEntry 指向 user32.dll 時(shí)),但是當(dāng)我們遞歸調(diào)用 LdrpMapAndSnapDependency() 依賴 gdi32.dll - PrevEntry 將用于 user32.dllCurEntry 用于 gdi32.dll),我們不直接調(diào)用LdrpSnapModule(LoadContext);而是LdrpQueueWork(LoadContext);.

                  So, if LoadContext->PrevEntry (say we load user32.dll. In the first call to LdrpMapAndSnapDependency(), LoadContext->PrevEntry will be always 0 (when CurEntry points to user32.dll), but when we recursively call LdrpMapAndSnapDependency() for it dependency gdi32.dll - PrevEntry will be for user32.dll and CurEntry for gdi32.dll), we do not direct call LdrpSnapModule(LoadContext); but LdrpQueueWork(LoadContext);.

                  LdrpQueueWork() 很簡(jiǎn)單:

                  void LdrpQueueWork(LDRP_LOAD_CONTEXT* LoadContext)
                  {
                      if (0 <= ctx->pstatus)
                      {
                          EnterCriticalSection(&LdrpWorkQueueLock);
                  
                          InsertHeadList(&LdrpWorkQueue, &LoadContext->WorkQueueListEntry);
                  
                          LeaveCriticalSection(&LdrpWorkQueueLock);
                  
                          if (LdrpMapAndSnapWork && !RtlGetCurrentPeb()->Ldr->ShutdownInProgress)
                          {
                              SubmitThreadpoolWork(LdrpMapAndSnapWork);//TpPostWork
                          }
                      }
                  }
                  

                  我們將 LoadContext 插入到 LdrpWorkQueue 中,如果Parallel loader"已啟動(dòng) (LdrpMapAndSnapWork != 0) 而不是 ShutdownInProgress - 我們將工作提交到加載器池.但是即使池沒(méi)有初始化(比如因?yàn)?Detours 存在) - 也不會(huì)出現(xiàn)錯(cuò)誤 - 我們?cè)?LdrpDrainWorkQueue() 中處理這個(gè)任務(wù).

                  We insert LoadContext to LdrpWorkQueue and if "Parallel loader" is started (LdrpMapAndSnapWork != 0) and not ShutdownInProgress - we submit work to loader pool. But even if the pool is not initialized (say because Detours exist) - there will be no error - we process this task in LdrpDrainWorkQueue().

                  在工作線程回調(diào)中執(zhí)行:

                  In a worker thread callback, this is executed:

                  void LdrpWorkCallback()
                  {
                      if (LdrpDetourExist) return;
                  
                      EnterCriticalSection(&LdrpWorkQueueLock);
                  
                      PLIST_ENTRY Entry = RemoveEntryList(&LdrpWorkQueue);
                  
                      if (Entry != &LdrpWorkQueue)
                      {
                          ++LdrpWorkInProgress;
                          LdrpUpdateStatistics()
                      }
                  
                      LeaveCriticalSection(&LdrpWorkQueueLock);
                  
                      if (Entry != &LdrpWorkQueue)
                      {
                          LdrpProcessWork(CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry), FALSE);
                      }
                  }
                  

                  我們只需從 LdrpWorkQueue 中彈出一個(gè)條目,將其轉(zhuǎn)換為 LDRP_LOAD_CONTEXT* (CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry)) 并調(diào)用 <代碼>void LdrpProcessWork(LDRP_LOAD_CONTEXT* LoadContext, BOOLEAN LoadOwner).

                  We simply popup an entry from LdrpWorkQueue, convert it to LDRP_LOAD_CONTEXT* (CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry)) and call void LdrpProcessWork(LDRP_LOAD_CONTEXT* LoadContext, BOOLEAN LoadOwner).

                  void LdrpProcessWork(LDRP_LOAD_CONTEXT* ctx, BOOLEAN LoadOwner)通常調(diào)用 LdrpSnapModule(LoadContext) 并在最后執(zhí)行下一個(gè)代碼:

                  void LdrpProcessWork(LDRP_LOAD_CONTEXT* ctx, BOOLEAN LoadOwner) in general calls LdrpSnapModule(LoadContext) and in the end the next code is executed:

                  if (!LoadOwner)
                  {
                      EnterCriticalSection(&LdrpWorkQueueLock);
                      BOOLEAN bSetEvent = --LdrpWorkInProgress == 1 && IsListEmpty(&LdrpWorkQueue);
                      LeaveCriticalSection(&LdrpWorkQueueLock);
                      if (bSetEvent) ZwSetEvent(LdrpWorkCompleteEvent, 0);
                  }
                  

                  所以,如果我們不是LoadOwner(在工作線程中),我們遞減LdrpWorkInProgress,如果LdrpWorkQueue 為空,則信號(hào)LdrpWorkCompleteEvent(LoadOwner 可以等待).

                  So, if we are not LoadOwner (in worked thread), we decrement LdrpWorkInProgress, and if LdrpWorkQueue is empty then signal LdrpWorkCompleteEvent (LoadOwner can wait on it).

                  最后,LdrpDrainWorkQueue()LoadOwner(主線程)被調(diào)用到drain".工作隊(duì)列.它可以彈出并直接執(zhí)行由 LdrpQueueWork() 推送到 LdrpWorkQueue 的任務(wù),但不會(huì)被工作線程彈出或因?yàn)椴⑿屑虞d器被禁用(在這種情況下LdrpQueueWork() 也推送 LDRP_LOAD_CONTEXT 但并沒(méi)有真正將工作發(fā)布到工作線程),最后等待(如果需要)LdrpWorkCompleteEventLdrpLoadCompleteEvent 事件.

                  and finally, LdrpDrainWorkQueue() is called from LoadOwner (primary thread) to "drain" the WorkQueue. It can possible pop and directly execute tasks pushed to LdrpWorkQueue by LdrpQueueWork(), and yet is not popped by worked threads or because parallel loader is disabled (in this case LdrpQueueWork() also push LDRP_LOAD_CONTEXT but not really post work to worked thread), and finally wait (if need) on LdrpWorkCompleteEvent or LdrpLoadCompleteEvent events.

                  enum DRAIN_TASK {
                      WaitLoadComplete, WaitWorkComplete
                  };
                  
                  void LdrpDrainWorkQueue(DRAIN_TASK task)
                  {
                      BOOLEAN LoadOwner = FALSE;
                  
                      HANDLE hEvent = task ? LdrpWorkCompleteEvent : LdrpLoadCompleteEvent;
                  
                      for(;;)
                      {
                          PLIST_ENTRY Entry;
                  
                          EnterCriticalSection(&LdrpWorkQueueLock);
                  
                          if (LdrpDetourExist && task == WaitLoadComplete)
                          {
                              if (!LdrpWorkInProgress)
                              {
                                  LdrpWorkInProgress = 1;
                                  LoadOwner = TRUE;
                              }
                              Entry = &LdrpWorkQueue;
                          }
                          else
                          {
                              Entry = RemoveHeadList(&LdrpWorkQueue);
                  
                              if (Entry == &LdrpWorkQueue)
                              {
                                  if (!LdrpWorkInProgress)
                                  {
                                      LdrpWorkInProgress = 1;
                                      LoadOwner = TRUE;
                                  }
                              }
                              else
                              {
                                  if (!LdrpDetourExist)
                                  {
                                      ++LdrpWorkInProgress;
                                  }
                                  LdrpUpdateStatistics();
                              }
                          }
                          LeaveCriticalSection(&LdrpWorkQueueLock);
                  
                          if (LoadOwner)
                          {
                              NtCurrentTeb()->LoadOwner = 1;
                              return;
                          }
                  
                          if (Entry != &LdrpWorkQueue)
                          {
                              LdrpProcessWork(CONTAINING_RECORD(Entry, LDRP_LOAD_CONTEXT, WorkQueueListEntry), FALSE);
                          }
                          else
                          {
                              ZwWaitForSingleObject(hEvent, 0, 0);
                          }
                      }
                  }
                  

                • void LdrpDropLastInProgressCount()
                  {
                    NtCurrentTeb()->LoadOwner = 0;
                    EnterCriticalSection(&LdrpWorkQueueLock);
                    LdrpWorkInProgress = 0;
                    LeaveCriticalSection(&LdrpWorkQueueLock);
                    ZwSetEvent(LdrpLoadCompleteEvent);
                  }
                  

                • 這篇關(guān)于為什么在 Win32 控制臺(tái)應(yīng)用程序啟動(dòng)時(shí)會(huì)出現(xiàn)三個(gè)意外的工作線程?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

                  【網(wǎng)站聲明】本站部分內(nèi)容來(lái)源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問(wèn)題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請(qǐng)聯(lián)系我們刪除處理,感謝您的支持!

                  相關(guān)文檔推薦

                  In what ways do C++ exceptions slow down code when there are no exceptions thown?(當(dāng)沒(méi)有異常時(shí),C++ 異常會(huì)以何種方式減慢代碼速度?)
                  Why catch an exception as reference-to-const?(為什么要捕獲異常作為對(duì) const 的引用?)
                  When and how should I use exception handling?(我應(yīng)該何時(shí)以及如何使用異常處理?)
                  Scope of exception object in C++(C++中異常對(duì)象的范圍)
                  Catching exceptions from a constructor#39;s initializer list(從構(gòu)造函數(shù)的初始化列表中捕獲異常)
                  Difference between C++03 throw() specifier C++11 noexcept(C++03 throw() 說(shuō)明符 C++11 noexcept 之間的區(qū)別)
                    <bdo id='S1H1M'></bdo><ul id='S1H1M'></ul>

                      1. <legend id='S1H1M'><style id='S1H1M'><dir id='S1H1M'><q id='S1H1M'></q></dir></style></legend>
                        <i id='S1H1M'><tr id='S1H1M'><dt id='S1H1M'><q id='S1H1M'><span id='S1H1M'><b id='S1H1M'><form id='S1H1M'><ins id='S1H1M'></ins><ul id='S1H1M'></ul><sub id='S1H1M'></sub></form><legend id='S1H1M'></legend><bdo id='S1H1M'><pre id='S1H1M'><center id='S1H1M'></center></pre></bdo></b><th id='S1H1M'></th></span></q></dt></tr></i><div class="qwawimqqmiuu" id='S1H1M'><tfoot id='S1H1M'></tfoot><dl id='S1H1M'><fieldset id='S1H1M'></fieldset></dl></div>

                            <small id='S1H1M'></small><noframes id='S1H1M'>

                            <tfoot id='S1H1M'></tfoot>
                              <tbody id='S1H1M'></tbody>

                          • 主站蜘蛛池模板: 手机av在线 | 日本中文字幕一区 | 99婷婷| 黄色大片免费在线观看 | 日韩中文字幕第一页 | 成年人一级片 | 国产精品2区 | 在线免费播放av | 日本特级淫片 | 九九九免费视频 | 国产探花视频在线观看 | 一级黄色大片 | 国产无遮挡又黄又爽免费网站 | 日本少妇中文字幕 | 亚洲免费在线观看视频 | 日本三级韩国三级美三级91 | 亚洲精品自拍视频 | 欧美精品黄色 | 一级香蕉视频 | 亚洲欧美中文字幕 | 日日不卡av | 他揉捏她两乳不停呻吟动态图 | 国产欧美日韩一区二区三区 | 日本不卡一区二区 | 在线免费看黄网站 | 97免费在线视频 | 免费成人小视频 | 黄色国产片| 欧美午夜理伦三级在线观看 | 91人人爽| 久久久成人免费视频 | 免费99精品国产自在在线 | 日韩欧美在线观看视频 | 久久香蕉精品 | 亚洲成人毛片 | av手机天堂 | 国产免费一级片 | 亚洲综合精品 | 欧美视频一二三区 | 中文字幕1区 | 人人澡人人爽 |