(1)全局變量echoLabel的使用,由於收發消息都在work線程中執行,且wok線程與主線程間的通信用的是SendMessage,暫時不會有問題,但有隱患;
(2)由SENDMEG結構體組成的鏈表的使用,用兩個指針分別指向鏈表的頭尾。在主線程中Insert節點,在work線程中Delete節點,問題就出現在這兩個函數中對兩個指針的操作。
CreatThread 與 _beginthreadex這三個函數的區別
CreatThread是Win32 API函數,而_beginthreadex屬於C RunTime函數,_beginthreadex內部調用了CreatThread。
爲什麼要有這樣的兩個創建線程的函數呢?最重要在於CreatThread在一種應用場景下有一個很大的缺陷,在使用CreatThread的情況下調用C++ RunTimeLibrary的函數,而被調用的函數使用了全局變量(確切的說是要求tiddata結構的全局變量,這個結構下面有解釋),這樣的話會出現不安全的問題。
不安全指的是內存泄露的問題,那麼是怎麼造成的,爲什麼_beginthreadex沒有這樣的問題?
要求tiddata結構的C RunTime函數在被調用後會有下面這些動作:
C RunTime函數試圖TlsGetalue獲取線程數據結構的地址,如果沒有獲取到,函數就會現場分配一個 tiddata結構,並且和線程相關聯。如果不通_endthreadex函數來終結線程的話,這個結構將不會被撤銷,內存泄漏就會出現了。但通常情況下,我們都不推薦使用_endthreadex函數來結束線程,因爲裏面包含了ExitThread調用。
CreateThread函數不產生這樣的tiddata結構,而_beginthreadex在產生線程的同時,還構建了一個堆結構(tiddata結構,通過線程本地存貯器與線程關聯起來),這個堆結構用來保存線程入口函數地址和一些數據,比如說errno之類的線程全局變量。我認爲tiddata結構的由來是這樣的,多線程版本下的CTL(C RunTime Library)函數與單線程版本下的區別主要是在對使用了全局變量的那些函數實現上,在多線程情況下使用全局變量會有很多預料不到的事,所以纔會有同步機制,多線程版本的CTL對此的應對措施就是在函數中使用tiddata結構,用來讀取和保存全局變量。
在《Win32多線程程序設計》中總結了幾條準則,何時使用_beginthreadex。
1 使用malloc()和free(),或是new和delete
2 使用stdio.h或io.h裏面聲明的任何函數
3 使用浮點變量或浮點運算函數
4 調用任何一個使用了靜態緩衝區的runtime函數,比如:asctime(),strtok()或rand()
注:全局變量errno用來存放錯誤原因,效果跟Win32平臺下的GetLastError()一樣。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jsswg0209/archive/2009/10/20/4703334.aspx
--------------------------
聯繫:
CreateThread、_beginthread和_beginthreadex都是用來啓動線程的。
區別:
_beginthread是_beginthreadex的功能子集,_beginthreadex是微軟的C/C++運行時庫函數,CreateThread是操作系統的函數。雖然_beginthread內部是調用_beginthreadex但他屏蔽了象安全特性這樣的功能,所以_beginthread與CreateThread不是同等級別,_beginthreadex和CreateThread在功能上完全可替代,我們就來比較一下_beginthreadex與CreateThread!
<<Windows核心編程>>中有很詳細地介紹:
注意:若要創建一個新線程,絕對不要使用CreateThread,而應使用_beginthreadex.
Why?考慮標準C運行時庫的一些變量和函數,如errno,這是一個全局變量。全局變量用於
多線程會出什麼事,你一定知道的了。故必須存在一種機制,使得每個線程能夠引用它自己的
errno變量,又不觸及另一線程的errno變量._beginthreadex就爲每個線程分配自己的
tiddata內存結構。該結構保存了許多像errno這樣的變量和函數的值、地址(自己看去吧)。
通過線程局部存儲將tiddata與線程聯繫起來。具體實現在Threadex.c中有。
結束線程使用函數_endthreadex函數,釋放掉線程的tiddata數據塊。
CRT的函數庫在線程出現之前就已經存在,所以原有的CRT不能真正支持線程,這導致我們在編程的時候有了CRT庫的選擇,在MSDN中查閱CRT的函數時都有:
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
這樣的提示!
對於線程的支持是後來的事!
這也導致了許多CRT的函數在多線程的情況下必須有特殊的支持,不能簡單的使用CreateThread就OK。
大多的CRT函數都可以在CreateThread線程中使用,看資料說只有signal()函數不可以,會導致進程終止!但可以用並不是說沒有問題!
有些CRT的函數象malloc(), fopen(), _open(), strtok(), ctime(), 或localtime()等函數需要專門的線程局部存儲的數據塊,這個數據塊通常需要在創建線程的時候就建立,如果使用CreateThread,這個數據塊就沒有建立,然後會怎樣呢?在這樣的線程中還是可以使用這些函數而且沒有出錯,實際上函數發現這個數據塊的指針爲空時,會自己建立一個,然後將其與線程聯繫在一起,這意味着如果你用CreateThread來創建線程,然後使用這樣的函數,會有一塊內存在不知不覺中創建,遺憾的是,這些函數並不將其刪除,而CreateThread和ExitThread也無法知道這件事,於是就會有Memory Leak,在線程頻繁啓動的軟件中(比如某些服務器軟件),遲早會讓系統的內存資源耗盡!
_beginthreadex(內部也調用CreateThread)和_endthreadex就對這個內存塊做了處理,所以沒有問題!(不會有人故意用CreateThread創建然後用_endthreadex終止吧,而且線程的終止最好不要顯式的調用終止函數,自然退出最好!)
談到Handle的問題,_beginthread的對應函數_endthread自動的調用了CloseHandle,而_beginthreadex的對應函數_endthreadex則沒有,所以CloseHandle無論如何都是要調用的不過_endthread可以幫你執行自己不必寫,其他兩種就需要自己寫!(Jeffrey Richter強烈推薦儘量不用顯式的終止函數,用自然退出的方式,自然退出當然就一定要自己寫CloseHandle)