創建線程的內幕(6)

      當調用CreateThread函數後,線程內核對象的使用計數初始化爲2,暫停計數被初始化爲1,退出代碼被設爲STILL_ACTIVE(0x103),並且對象被設爲未觸發狀態。

      一旦創建線程內核對象,系統便分配內存,供線程堆棧使用。此內存是從進程地址空間內分配的,線程沒有自己的地址空間。然後系統將CreateThread函數傳入的pvParam參數值放入堆棧最上端,緊接着它下方是pfnStartAddr參數的值。

      每個線程都有自己的一組cpu寄存器,稱爲線程上下文。其反應線程上一次執行時的cpu寄存器狀態。cpu寄存器狀態保存在一個CONTEXT結構中,CONTEXT結構本身保存在線程內核對象中。


      當線程內核對象初始化的時候,CONTEXT結構中的堆棧指針寄存器被設爲pfnStartAddr在線程堆棧中的地址。而指令指針寄存器被設爲RtlUserThreadStart函數(此函數是NTDLL.dll導出的)的地址。

      當初始化完成後,系統會檢查CREATE_SUSPENDED標識是否已被傳給CreateThread函數,如果沒有傳遞,系統將線程的掛起技術遞減至0;隨後,線程就可以調度給一個處理器去執行了。然後,系統在實際的cpu寄存器中加載上一次在線程context中保存的值。現在,線程可以在其進程的地址空間中執行代碼並處理數據了。


      RtlUserThreadStart函數是線程的實際開始執行的函數。新線程執行RtlUserThreadStart函數時,將發生:

         1.設置一個結構化異常處理幀(SEH)。P159

         2.系統調用線程函數。

         3.線程函數返回時,RtlUserThreadStart調用ExitThread,將你的線程函數的返回值傳給它。線程內核對象計數遞減,而後線程停止執行。

         4.如果線程產生了一個未被處理的異常,RtlUserThreadStart函數所設置的SEH會處理這個異常。通常會發出一個消息提醒框,當用戶關閉框時,RtlUserThreadStart會調用              ExitProcess來終止整個進程,而不是終止有問題的線程。

      注意,在RtlUserThreadStart函數內,線程會調用“ExitThread”和“ExitProcess”。說明線程永遠不能退出此函數;始終在其內部消亡。所以RtlUserThreadStart返回值爲VOID(因爲它永遠不會返回)。如果在沒有強行“殺死”線程的情況下嘗試返回,它會返回隨機位置(因爲線程堆棧上沒有函數返回地址),這會引起違規操作。【線程被包裹在RtlThreadStart函數之內】

      


       進程的主線程在初始化時,其指令指針會被設爲同一個未文檔化的RtlUserThreadStart。當RtlUserThreadStart開始執行時,它會調用C/C++運行庫啓動代碼,後者繼而調用你的_tmain函數或_tWinMain函數。你的入口點函數返回,運行庫啓動代碼調用ExitProcess。所以對於主線程而言,主線程永遠不會返回到RtlUserThreadStart函數。



發佈了40 篇原創文章 · 獲贊 19 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章