欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++線程退出的四種方法小結(jié)

 更新時間:2023年07月25日 15:32:37   作者:Jimmy1224  
本文主要介紹了C/C++線程退出的四種方法小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

想要終止線程的運(yùn)行,可以使用以下方法:

  • 線程函數(shù)返回(最好使用該方法)。
  • 同一個進(jìn)程或另一個進(jìn)程中的線程調(diào)用TerminateThread函數(shù)(應(yīng)避免使用該方法)。
  • 通過調(diào)用ExitThread函數(shù),線程將自行撤消(最好不使用該方法)。
  • ExitProcess和TerminateProcess函數(shù)也可以用來終止線程的運(yùn)行(應(yīng)避免使用該方法)。

下面將詳細(xì)介紹終止線程運(yùn)行的方法:1-4,并說明線程終止運(yùn)行時會出現(xiàn)何種情況:5。

為了說明以下線程的退出時發(fā)生的動作,引入以下測試代碼:

class ?TTThread
{
public:
? ? /** @name Constructors and Destructor*/
? ? TTThread();
? ? virtual ~TTThread();
public:
?? ?//線程創(chuàng)建函數(shù)
?? ?BOOL Create();
?? ?//線程銷毀,在這里驗(yàn)證TerminateThread
?? ?void Destory();
?? ?//線程等待
?? ?BOOL Wait(DWORD dwWaitTime);
?? ?inline DWORD GetThreadID() { return m_dwThreadID; }
protected:
?? ?//線程函數(shù)邏輯接口,子類繼承
?? ?//在這里驗(yàn)證ExitThread和正常退出操作
?? ?virtual unsigned Process();
private:
?? ?//線程入口地址
?? ?static unsigned ?__stdcall _threadProc(void *lpParam);
private:
?? ?HANDLE?? ??? ?m_hThread;
?? ?DWORD?? ??? ?m_dwThreadID;
};
//C++對象
class CObj
{
public:
? ? CObj()
? ? {
? ? ? printf("CObj create...\n");
? ? }
? ? ~CObj()
? ? {
? ? ? ? printf("CObj delete...\n");
? ? }
};
//線程測試類
class CTestThread : public TTThread
{
public:
? ? virtual unsigned Process()
? ? {
? ? ? ?return 0;
? ? }
};

線程函數(shù)返回

始終都應(yīng)該將線程設(shè)計(jì)成這樣的形式,即當(dāng)想要線程終止運(yùn)行時,它們就能夠返回。這是確保所有線程資源被正確地清除的唯一辦法。
如果線程能夠返回,就可以確保下列事項(xiàng)的實(shí)現(xiàn):
(1)在線程函數(shù)中創(chuàng)建的所有C++對象均將通過它們的析構(gòu)函數(shù)進(jìn)行釋放。
(2)操作系統(tǒng)將正確地釋放線程堆棧使用的內(nèi)存。
(3)系統(tǒng)將線程的退出代碼(在線程的內(nèi)核對象中維護(hù))設(shè)置為線程函數(shù)的返回值。
(4)系統(tǒng)將遞減線程內(nèi)核對象的使用計(jì)數(shù)。

其中,(1)(2)兩點(diǎn)在編碼中需要特別關(guān)注的,這個在編碼規(guī)范上比較重要。(jimmy注)

測試代碼:

int _tmain(int argc, _TCHAR* argv[])
{
? ? printf("main thread begin...\n");
? ? //創(chuàng)建線程
? ? CTestThread ?workthread;
? ? workthread.Create();
? ? //等待線程結(jié)束,此時不會執(zhí)行Destroy函數(shù),線程正常結(jié)束
? ? if (!workthread.Wait(3 * 1000))
? ? {
? ? ? ? //超時銷毀線程 ? ? ??
? ? ? ? workthread.Destory();
? ? }
? ? printf("main thread end...\n");
? ? return 0;
}

測試結(jié)果:

main thread begin...
CObj create...//c++對象創(chuàng)建
current index:0
current index:1
current index:2
current index:3
current index:4
CObj delete...//C++對象析構(gòu)以及線程申請的內(nèi)存正確釋放
main thread end... 
請按任意鍵繼續(xù). . .

TerminateThread函數(shù)

調(diào)用TerminateThread函數(shù)也能夠終止線程的運(yùn)行,其函數(shù)原型如下:

BOOL TerminateThread( 
  HANDLE hThread, 
  DWORD dwExitCode); 

TerminateThread能夠撤消任何線程,其中hThread參數(shù)用于標(biāo)識被終止運(yùn)行的線程的句柄。當(dāng)線程終止運(yùn)行時,它的退出代碼成為你作為dwExitCode參數(shù)傳遞的值。同時,線程的內(nèi)核對象的使用計(jì)數(shù)也被遞減。

注意TerminateThread函數(shù)是異步運(yùn)行的函數(shù),也就是說,它告訴系統(tǒng)你想要線程終止運(yùn)行,但是,當(dāng)函數(shù)返回時,不能保證線程被撤消。如果需要確切地知道該線程已經(jīng)終止運(yùn)行,必須調(diào)用WaitForSingleObject或者類似的函數(shù),傳遞線程的句柄。

用TerminateThread銷毀線程示例代碼:

// 在另一個線程中進(jìn)行調(diào)用,這里是在主線程終止測試線程
void TTThread::Destory()
{
    if (m_hThread)
    {
        //TerminateThread以異步方式執(zhí)行,函數(shù)返回不代表線程結(jié)束,
        //線程函數(shù)停止執(zhí)行,位置隨機(jī),類對象不會被析構(gòu)導(dǎo)致內(nèi)存泄漏
        ::TerminateThread(m_hThread, 0);
        //等待線程結(jié)束
        ::WaitForSingleObject(m_hThread, 500);
        ::CloseHandle(m_hThread);
        m_hThread = 0;
        m_dwThreadID = 0;
        printf("end destroy\n");
    }
}

設(shè)計(jì)良好的應(yīng)用程序從來不使用這個函數(shù),因?yàn)楸唤K止運(yùn)行的線程收不到它被撤消的通知。并且,如果使用TerminateThread,那么在擁有線程的進(jìn)程終止運(yùn)行之前,系統(tǒng)不撤消該線程的堆棧,造成內(nèi)存不能及時釋放。

int _tmain(int argc, _TCHAR* argv[])
{
? ? printf("main thread begin...\n");
? ? //創(chuàng)建線程
? ? CTestThread ?workthread;
? ? workthread.Create();
? ? //等待線程結(jié)束,此時會執(zhí)行Destroy函數(shù),線程異常結(jié)束
? ? if (!workthread.Wait(1 * 1000))
? ? {
? ? ? ? //超時,主線程銷毀測試線程 ? ? ??
? ? ? ? workthread.Destory();
? ? }
? ? printf("main thread end...\n");
? ? return 0;
}

測試結(jié)果

main thread begin...
CObj create...
current index:0
current index:1
end destroy
main thread end...
//CObj沒有執(zhí)行析構(gòu)函數(shù),沒有及時釋放線程申請的_tiddata內(nèi)存
請按任意鍵繼續(xù). . .

ExitThread函數(shù)

可以讓線程調(diào)用ExitThread函數(shù),以便強(qiáng)制終止當(dāng)前線程運(yùn)行,其函數(shù)原型:

VOID ExitThread(DWORD dwExitCode);

該函數(shù)將終止線程的運(yùn)行,并導(dǎo)致操作系統(tǒng)清除該線程使用的所有操作系統(tǒng)資源。但是,C++資源(如C++類對象)將不被析構(gòu)。由于這個原因,最好從線程函數(shù)返回,而不是通過調(diào)用ExitThread來返回。
當(dāng)然,可以使用ExitThread的dwExitThread參數(shù)告訴系統(tǒng)將線程的退出代碼設(shè)置為什么。ExitThread函數(shù)并不返回任何值,因?yàn)榫€程已經(jīng)終止運(yùn)行,不能執(zhí)行更多的代碼。

注意終止線程運(yùn)行的最佳方法是讓它的線程函數(shù)返回。但是,如果使用本節(jié)介紹的方法,應(yīng)該知道ExitThread函數(shù)是Windows用來撤消線程的函數(shù)。如果編寫C/C++代碼,那么決不應(yīng)該調(diào)用ExitThread。應(yīng)該使用Visual C++運(yùn)行期庫函數(shù)_endthreadex,因?yàn)開endthreadex可以確保,及時釋放線程申請的tiddata內(nèi)存。

測試代碼

class CTestThread : public TTThread
{
public:
? ? virtual unsigned Process()
? ? {
? ? ? ? CObj obj;
? ? ? ?for (int i = 0; i < 5; i++)
? ? ? ?{
? ? ? ? ? ?Sleep(400);
? ? ? ? ? ?printf("current index:%d\n", i);
? ? ? ? ? ?//當(dāng)前線程退出
? ? ? ? ? ?if (i == 3)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?printf("make thread end...\n");
? ? ? ? ? ? ? ?//_endthreadex(0);
? ? ? ? ? ? ? ?ExitThread(0);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?return 0;
? ? }
};
int _tmain(int argc, _TCHAR* argv[])
{
? ? printf("main thread begin...\n");
? ? //創(chuàng)建線程
? ? CTestThread ?workthread;
? ? workthread.Create();
?? ?//等待線程結(jié)束
? ? if (workthread.Wait(3 * 1000))
? ? {
? ? ? ? printf("the test thread end...");
? ? }
? ? printf("main thread end...\n");
? ? return 0;
}

測試結(jié)果

main thread begin...
CObj create...
current index:0
current index:1
current index:2
current index:3
make thread end...線程被中斷執(zhí)行,造成tiddata和CObj內(nèi)存泄漏
the test thread end...main thread end...
請按任意鍵繼續(xù). . .

在進(jìn)程終止運(yùn)行時撤消線程

ExitProcess和TerminateProcess函數(shù)也可以用來終止線程的運(yùn)行。差別在于這些線程將會使終止運(yùn)行的進(jìn)程中的所有線程全部終止運(yùn)行。另外,由于整個進(jìn)程已經(jīng)被關(guān)閉,進(jìn)程使用的所有資源肯定已被清除。這當(dāng)然包括所有線程的堆棧。這兩個函數(shù)會導(dǎo)致進(jìn)程中的剩余線程被強(qiáng)制撤消,就像從每個剩余的線程調(diào)用TerminateThread一樣。顯然,這意味著正確的應(yīng)用程序清除沒有發(fā)生,即C++對象撤消函數(shù)沒有被調(diào)用,數(shù)據(jù)沒有轉(zhuǎn)至磁盤等等。

線程終止運(yùn)行時發(fā)生的操作

當(dāng)線程終止運(yùn)行時,會發(fā)生下列操作:
(1)線程擁有的所有用戶對象均被釋放。在Windows中,大多數(shù)對象是由包含創(chuàng)建這些對象的線程的進(jìn)程擁有的。但是一個線程擁有兩個用戶對象,即窗口和掛鉤。當(dāng)線程終止運(yùn)行時,系統(tǒng)會自動撤消任何窗口,并且卸載線程創(chuàng)建的或安裝的任何掛鉤。其他對象只有在擁有線程的進(jìn)程終止運(yùn)行時才被撤消。
(2)線程的退出代碼從STILL_ACTIVE改為傳遞給ExitThread或TerminateThread的代碼。
(3)線程內(nèi)核對象的狀態(tài)變?yōu)橐淹ㄖ?br />(4)如果線程是進(jìn)程中最后一個活動線程,系統(tǒng)也將進(jìn)程視為已經(jīng)終止運(yùn)行。
(5)線程內(nèi)核對象的使用計(jì)數(shù)遞減1。

當(dāng)一個線程終止運(yùn)行時,在與它相關(guān)聯(lián)的線程內(nèi)核對象的所有未結(jié)束的引用關(guān)閉之前,該內(nèi)核對象不會自動被釋放。
一旦線程不再運(yùn)行,系統(tǒng)中就沒有別的線程能夠處理該線程的句柄。然而別的線程可以調(diào)用GetExitcodeThread來檢查由hThread標(biāo)識的線程是否已經(jīng)終止運(yùn)行。如果它已經(jīng)終止運(yùn)行,則確定它的退出代碼:
函數(shù)原型:

BOOL GetExitCodeThread( 
  HANDLE hThread, 
  PDWORD pdwExitCode); 

退出代碼的值在pdwExitCode指向的DWORD中返回。如果調(diào)用GetExitCodeThread時線程尚未終止運(yùn)行,該函數(shù)就用STILL_ACTIVE標(biāo)識符(定義為0x103)填入DWORD。如果該函數(shù)運(yùn)行成功,便返回TRUE。

線程基類整體實(shí)現(xiàn):

/*******************************************************?
?* ?@file ? ? ?TTThread.cpp
?* ?@author ? ?jimmy
?* ?@brief ? windows線程處理的包裝
?******************************************************/
#include "stdafx.h"
#include "TTThread.h"
TTThread::TTThread()
:m_hThread(0)
{
}
TTThread::~TTThread()
{
?? ?if (m_hThread)
? ? {
? ? ? ? ::CloseHandle(m_hThread);
? ? }
?? ?m_hThread = 0;
}
/**************************************************************
* ?@brief : TTThread::create
* ? ??
* ?@param : -none
* ? ??
* ?@return : BOOL
* ? ??
* ?@author : Jimmy
* ? ??
* ?@date : 2019/2/13 星期三
* ? ??
* ?@note : 線程創(chuàng)建函數(shù)
***************************************************************/
BOOL TTThread::Create()
{
? ? m_hThread = (HANDLE)_beginthreadex(0,0, _threadProc, this, 0, (unsigned*)&m_dwThreadID);
? ? if (0 == m_hThread)
? ? {
? ? ? ? m_dwThreadID = 0;
? ? }
?? ?return m_hThread >(HANDLE)1;
}
void TTThread::Destory()
{
?? ?if (m_hThread)
?? ?{
?? ??? ?//TerminateThread以異步方式執(zhí)行,函數(shù)返回不代表線程結(jié)束,
? ? ? ? //線程函數(shù)停止執(zhí)行,位置隨機(jī),類對象不會被析構(gòu)導(dǎo)致內(nèi)存泄漏
? ? ? ? ::TerminateThread(m_hThread, 0);
? ? ? ? //等待線程結(jié)束
? ? ? ? ::WaitForSingleObject(m_hThread, 500);
?? ??? ?::CloseHandle(m_hThread);
?? ??? ?m_hThread = 0;
?? ??? ?m_dwThreadID = 0;
? ? ? ? printf("end destroy\n");
?? ?}
}
BOOL TTThread::Wait(DWORD dwWaitTime)
{
?? ?if (m_hThread == 0)
?? ??? ?return TRUE;
?? ?return (::WaitForSingleObject(m_hThread, dwWaitTime) != WAIT_TIMEOUT);
}
unsigned TTThread::Process()
{
?? ?return 0;
}
unsigned __stdcall TTThread::_threadProc(void *lpParam)
{
?? ?TTThread* pThread = (TTThread*)lpParam;
?? ?assert(pThread);
?? ?if (pThread != 0)
?? ?{
?? ??? ?pThread->Process();
?? ?}
?? ?return 0;
}

參考文章:
https://www.cnblogs.com/arsblog/p/4829729.html

完整線程類代碼參見github:
https://github.com/jinxiang1224/cpp/tree/master/thread

到此這篇關(guān)于C/C++線程退出的四種方法小結(jié)的文章就介紹到這了,更多相關(guān)C/C++線程退出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中auto類型說明符詳解(附易錯實(shí)例)

    C++中auto類型說明符詳解(附易錯實(shí)例)

    這篇文章主要給大家介紹了關(guān)于C++中auto類型說明符的相關(guān)資料,文中還附易錯實(shí)例,在C++11中引入了auto類型說明符,用它就能讓編譯器替我們?nèi)シ治霰磉_(dá)式所屬的類型,需要的朋友可以參考下
    2023-07-07
  • C語言自定義類型全解析

    C語言自定義類型全解析

    在C語言中自定義類型主要有結(jié)構(gòu)體類型、位段、枚舉類型、聯(lián)合體類型,自定義類型是面試常會碰到的內(nèi)容,今天我們來詳細(xì)了解一下它
    2022-02-02
  • C語言動態(tài)內(nèi)存的分配最全面分析

    C語言動態(tài)內(nèi)存的分配最全面分析

    動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動態(tài)內(nèi)存的管理
    2022-08-08
  • C++面試題之?dāng)?shù)a、b的值互換(不使用中間變量)

    C++面試題之?dāng)?shù)a、b的值互換(不使用中間變量)

    這篇文章主要介紹了不使用中間變量,C++實(shí)現(xiàn)數(shù)a、b的值互相轉(zhuǎn)換操作,感興趣的小伙伴們可以參考一下
    2016-07-07
  • C/C++ 中const關(guān)鍵字的用法小結(jié)

    C/C++ 中const關(guān)鍵字的用法小結(jié)

    C++中的const關(guān)鍵字的用法非常靈活,而使用const將大大改善程序的健壯性。這篇文章主要介紹了C/C++ 中const關(guān)鍵字的用法,需要的朋友可以參考下
    2020-02-02
  • C語言實(shí)現(xiàn)BMP圖像的讀寫功能

    C語言實(shí)現(xiàn)BMP圖像的讀寫功能

    這篇文章主要介紹了C語言實(shí)現(xiàn)BMP圖像的讀寫功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Linux中利用c語言刪除某個目錄下的文件

    Linux中利用c語言刪除某個目錄下的文件

    這篇文章主要給大家介紹了Linux中利用c語言刪除某個目錄下文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C語言詳解分析進(jìn)程控制中進(jìn)程終止的實(shí)現(xiàn)

    C語言詳解分析進(jìn)程控制中進(jìn)程終止的實(shí)現(xiàn)

    當(dāng)進(jìn)程完成執(zhí)行最后語句并且通過系統(tǒng)調(diào)用 exit() 請求操作系統(tǒng)刪除自身時,進(jìn)程終止。這時,進(jìn)程可以返回狀態(tài)值(通常為整數(shù))到父進(jìn)程(通過系統(tǒng)調(diào)用 wait())。所有進(jìn)程資源,如物理和虛擬內(nèi)存、打開文件和 I/O 緩沖區(qū)等,會由操作系統(tǒng)釋放
    2022-08-08
  • C語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用鏈表

    C語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用鏈表

    這篇文章主要為大家詳細(xì)介紹了c語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語言規(guī)律循環(huán)累加求和案例

    C語言規(guī)律循環(huán)累加求和案例

    這篇文章主要介紹了C語言規(guī)律循環(huán)累加求和案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論