亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

淺談 Windows 編程中的 Thread

2023-07-20 03:25:07
6
0

線程對于 Windows 編程人員來說,并不陌生,但是一直以來,我對它的了解也只是基本的使用層面。對于很多細節,也并不是很了解。這作為一個 Windows 客戶端開發人員,可以說是非常尷尬了。所以,抽了一點時間,仔細梳理了一下線程相關的內容。順便記錄下來。

一些常識

  • 基本狀態:就緒,執行,阻塞
  • 堆公有、棧私有
  • 創建和結束所需要的系統開銷:小
  • 沒有自己的地址空間

創建線程

在 Windows 下創建一個線程,很自然的會想到

CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
    );
 

這個方法可以說對 Windows 應用開發人員并不陌生。當使用這個方法的時候,在平時使用的時候,比較多關注的就是 lpStartAddresslpParameter 。這是線程函數的入口以及參數。創建一個新線程之后,將會從這里開始執行。

但是對于 C++ 來說,其實有另一個方法

_ACRTIMP uintptr_t __cdecl _beginthreadex(
    _In_opt_  void*                    _Security,
    _In_      unsigned                 _StackSize,
    _In_      _beginthreadex_proc_type _StartAddress,
    _In_opt_  void*                    _ArgList,
    _In_      unsigned                 _InitFlag,
    _Out_opt_ unsigned*                _ThrdAddr
    );
 

在這里,_StartAddress_ArgList 則跟上述那兩個參數是類似的作用。
然而在這兩個方法的選擇中,《Windows 核心編程》早有公斷。

根據作者的說法是選擇 _beginthreadex 替代 CreateThread 。而原因則要從 _beginthreadex 的實現上說起。

_beginthreadex 在 Windows 下的實現也是調用了 CreateThread ,畢竟在 Windows 系統中,只認這一種創建線程的方式。但是在這之前,它還會做一些額外工作。創建一個線程數據塊( tiddata ),然后將入口和參數都保存到數據塊中,最后還要把數據塊保存在 TLS 中。之后還要初始化一個 SEH 幀,用來處理運行時產生的錯誤。然后在線程結束之前,釋放掉 tiddata 。那這樣看,確實要比 CreateThread 多做一些事情。

話說回來,如果不做這些事情,當然就會有問題。比較直接的問題就是內存泄漏。原因是,如果使用 CreateThread 創建線程,當調用一些運行庫函數的時候,會檢查這個 tiddata 。如果發現沒有,則會自己搞出一個,而這個在線程結束的時候,就不會被正確釋放,就出現了內存泄漏。

類似 errno 這種運行庫函數,需要反應正確的錯誤信息,如果不記錄線程相關信息,則會在多線程的時候出現錯誤,所以一個 tiddata 是必要的,這也說明了為什么這個 tiddata 無論什么情況都會存在。

所以綜上所述,在創建線程是,應該選擇 _beginthreadex

關于更詳細的 _beginthreadex 內容,參考 _beginthread, _beginthreadex 這篇文章是最好了

TLS

上邊說的 TLS。可謂是線程中不可缺少的東西。因為線程之間是共享地址空間的,所以當有一些每個線程自己所需要的數據的時候,就不那么方便。而 TLS 就是用來解決這個問題。存儲在 TLS 中的數據,對于每個線程之間,是互相隔離的。

結束線程

盡可能的讓線程執行完自然結束。不到萬不得已的時候,都不要使用 ExitThread 或者是 _endthreadex 。因為會使主調線程不正常返回,導致構造的 C++ 對象都不會析構;如果使用 ExitThread 還會造成 tiddata 不會被釋放。

后記

關于多線程編程其實坑不算少,唯有對 Thread 多一些了解,才能寫出更高質量的代碼。

0條評論
0 / 1000
Harper
20文章數
0粉絲數
Harper
20 文章 | 0 粉絲
原創

淺談 Windows 編程中的 Thread

2023-07-20 03:25:07
6
0

線程對于 Windows 編程人員來說,并不陌生,但是一直以來,我對它的了解也只是基本的使用層面。對于很多細節,也并不是很了解。這作為一個 Windows 客戶端開發人員,可以說是非常尷尬了。所以,抽了一點時間,仔細梳理了一下線程相關的內容。順便記錄下來。

一些常識

  • 基本狀態:就緒,執行,阻塞
  • 堆公有、棧私有
  • 創建和結束所需要的系統開銷:小
  • 沒有自己的地址空間

創建線程

在 Windows 下創建一個線程,很自然的會想到

CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
    );
 

這個方法可以說對 Windows 應用開發人員并不陌生。當使用這個方法的時候,在平時使用的時候,比較多關注的就是 lpStartAddresslpParameter 。這是線程函數的入口以及參數。創建一個新線程之后,將會從這里開始執行。

但是對于 C++ 來說,其實有另一個方法

_ACRTIMP uintptr_t __cdecl _beginthreadex(
    _In_opt_  void*                    _Security,
    _In_      unsigned                 _StackSize,
    _In_      _beginthreadex_proc_type _StartAddress,
    _In_opt_  void*                    _ArgList,
    _In_      unsigned                 _InitFlag,
    _Out_opt_ unsigned*                _ThrdAddr
    );
 

在這里,_StartAddress_ArgList 則跟上述那兩個參數是類似的作用。
然而在這兩個方法的選擇中,《Windows 核心編程》早有公斷。

根據作者的說法是選擇 _beginthreadex 替代 CreateThread 。而原因則要從 _beginthreadex 的實現上說起。

_beginthreadex 在 Windows 下的實現也是調用了 CreateThread ,畢竟在 Windows 系統中,只認這一種創建線程的方式。但是在這之前,它還會做一些額外工作。創建一個線程數據塊( tiddata ),然后將入口和參數都保存到數據塊中,最后還要把數據塊保存在 TLS 中。之后還要初始化一個 SEH 幀,用來處理運行時產生的錯誤。然后在線程結束之前,釋放掉 tiddata 。那這樣看,確實要比 CreateThread 多做一些事情。

話說回來,如果不做這些事情,當然就會有問題。比較直接的問題就是內存泄漏。原因是,如果使用 CreateThread 創建線程,當調用一些運行庫函數的時候,會檢查這個 tiddata 。如果發現沒有,則會自己搞出一個,而這個在線程結束的時候,就不會被正確釋放,就出現了內存泄漏。

類似 errno 這種運行庫函數,需要反應正確的錯誤信息,如果不記錄線程相關信息,則會在多線程的時候出現錯誤,所以一個 tiddata 是必要的,這也說明了為什么這個 tiddata 無論什么情況都會存在。

所以綜上所述,在創建線程是,應該選擇 _beginthreadex

關于更詳細的 _beginthreadex 內容,參考 _beginthread, _beginthreadex 這篇文章是最好了

TLS

上邊說的 TLS。可謂是線程中不可缺少的東西。因為線程之間是共享地址空間的,所以當有一些每個線程自己所需要的數據的時候,就不那么方便。而 TLS 就是用來解決這個問題。存儲在 TLS 中的數據,對于每個線程之間,是互相隔離的。

結束線程

盡可能的讓線程執行完自然結束。不到萬不得已的時候,都不要使用 ExitThread 或者是 _endthreadex 。因為會使主調線程不正常返回,導致構造的 C++ 對象都不會析構;如果使用 ExitThread 還會造成 tiddata 不會被釋放。

后記

關于多線程編程其實坑不算少,唯有對 Thread 多一些了解,才能寫出更高質量的代碼。

文章來自個人專欄
文章 | 訂閱
0條評論
0 / 1000
請輸入你的評論
0
0