當前位置:編程學習大全網 - 源碼下載 - 怎麽在dll中啟動線程

怎麽在dll中啟動線程

方法與普通的EXE沒有分別。

第6章 線程的基礎知識

1. 進程與線程有那些區別和聯系?

l 每個進程至少需要壹個線程。

l 進程由兩部分構成:進程內核對象,地址空間。線程也由兩部分組成:線程內核對象,操作系統用它來對線程實施管理。線程堆棧,用於維護線程在執行代碼時需要的所有函數參數和局部變量。

l 進程是不活潑的。進程從來不執行任何東西,它只是線程的容器。線程總是在某個進程環境中創建的,而且它的整個壽命期都在該進程中。

l 如果在單進程環境中,有多個線程正在運行,那麽這些線程將***享單個地址空間。這些線程能夠執行相同的代碼,對相同的數據進行操作。這些線程還能***享內核對象句柄,因為句柄表依賴於每個進程而不是每個線程存在。

l 進程使用的系統資源比線程多得多。實際上,線程只有壹個內核對象和壹個堆棧,保留的記錄很少,因此需要很少的內存。因此始終都應該設法用增加線程來解決編程問題,避免創建新的進程。但是許多程序設計用多個進程來實現會更好些。

2. 如何使用_beginthreadex函數?

使用方法與CreateThread函數相同,只是調用參數類型需要轉換。

3. 如何使用CreateThread函數?

當CreateThread被調用時,系統創建壹個線程內核對象。該線程內核對象不是線程本身,而是操作系統用來管理線程的較小的數據結構。使用時應當註意在不需要對線程內核進行訪問後調用CloseHandle函數關閉線程句柄。因為CreateThread函數中使用某些C/C++運行期庫函數時會有內存泄漏,所以應當盡量避免使用。

參數 含義

lpThreadAttributes 如果傳遞NULL該線程使用默認安全屬性。如果希望所有的子進程能夠繼承該線程對象的句柄,必須將它的bInheritHandle成員被初始化為TRUE。

dwStackSize 設定線程堆棧的地址空間。如果非0,函數將所有的存儲器保留並分配給線程的堆棧。如果是0,CreateThread就保留壹個區域,並且將鏈接程序嵌入.exe文件的/STACK鏈接程序開關信息指明的存儲器容量分配給線程堆棧。

lpStartAddress 線程函數的地址。

lpParameter 傳遞給線程函數的參數。

dwCreationFlags 如果是0,線程創建後立即進行調度。如果是CREATE_SUSPENDED,系統對它進行初始化後暫停該線程的運行。

LpThreadId 用來存放系統分配給新線程的ID。

4. 如何終止線程的運行?

(1) 線程函數返回(最好使用這種方法)。

這是確保所有線程資源被正確地清除的唯壹辦法。

如果線程能夠返回,就可以確保下列事項的實現:

在線程函數中創建的所有C++對象均將通過它們的撤消函數正確地撤消。

操作系統將正確地釋放線程堆棧使用的內存。

系統將線程的退出代碼設置為線程函數的返回值。

系統將遞減線程內核對象的使用計數。

(2) 調用ExitThread函數(最好不要使用這種方法)。

該函數將終止線程的運行,並導致操作系統清除該線程使用的所有操作系統資源。但是,C++資源(如C++類對象)將不被撤消。

(3) 調用TerminateThread函數(應該避免使用這種方法)。

TerminateThread能撤消任何線程。線程的內核對象的使用計數也被遞減。TerminateThread函數是異步運行的函數。如果要確切地知道該線程已經終止運行,必須調用WaitForSingleObject或者類似的函數。當使用返回或調用ExitThread的方法撤消線程時,該線程的內存堆棧也被撤消。但是,如果使用TerminateThread,那麽在擁有線程的進程終止運行之前,系統不撤消該線程的堆棧。

(4) 包含線程的進程終止運行(應該避免使用這種方法)。

由於整個進程已經被關閉,進程使用的所有資源肯定已被清除。就像從每個剩余的線程調用TerminateThread壹樣。這意味著正確的應用程序清除沒有發生,即C++對象撤消函數沒有被調用,數據沒有轉至磁盤等等。

壹旦線程不再運行,系統中就沒有別的線程能夠處理該線程的句柄。然而別的線程可以調用GetExitcodeThread來檢查由hThread標識的線程是否已經終止運行。如果它已經終止運行,則確定它的退出代碼。

5. 為什麽不要使用_beginthread函數和_endthread函數?

與_beginthreadex函數相比參數少,限制多。無法創建暫停的線程,無法取得線程ID。_endthread函數無參數,線程退出代碼必須為0。還有_endthread函數內部關閉了線程的句柄,壹旦退出將不能正確訪問線程句柄。

6. 如何對進程或線程的內核進行引用?

HANDLE GetCurrentProcess( );

HANDLE GetCurrentThread( );

這兩個函數都能返回調用線程的進程的偽句柄或線程內核對象的偽句柄。偽句柄只能在當前的進程或線程中使用,在其它線程或進程將不能訪問。函數並不在創建進程的句柄表中創建新句柄。調用這些函數對進程或線程內核對象的使用計數沒有任何影響。如果調用CloseHandle,將偽句柄作為參數來傳遞,那麽CloseHandle就會忽略該函數的調用並返回FALSE。

DWORD GetCurrentProcessId( );

DWORD GetCurrentThreadId( );

這兩個函數使得線程能夠查詢它的進程的唯壹ID或它自己的唯壹ID。

7. 如何將偽句柄轉換為實句柄?

HANDLE hProcessFalse = NULL;

HANDLE hProcessTrue = NULL;

HANDLE hThreadFalse = NULL;

HANDLE hThreadTrue = NULL;

hProcessFalse = GetCurrentProcess( );

hThreadFalse = GetCurrentThread( );

取得線程實句柄:

DuplicateHandle( hProcessFalse, hThreadFalse, hProcessFalse, &hThreadTrue, 0, FALSE, DUPLICATE_SAME_ACCESS );

取得進程實句柄:

DuplicateHandle( hProcessFalse, hProcessFalse, hProcessFalse, &hProcessTrue, 0, FALSE, DUPLICATE_SAME_ACCESS );

由於DuplicateHandle會遞增特定對象的使用計數,因此當完成對復制對象句柄的使用時,應該將目標句柄傳遞給CloseHandle,從而遞減對象的使用計數。

  • 上一篇:夢見養小白馬
  • 下一篇:短線指標有哪些
  • copyright 2024編程學習大全網