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

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

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

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

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

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

為了說(shuō)明以下線程的退出時(shí)發(fā)生的動(dòng)作,引入以下測(cè)試代碼:

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++對(duì)象
class CObj
{
public:
? ? CObj()
? ? {
? ? ? printf("CObj create...\n");
? ? }
? ? ~CObj()
? ? {
? ? ? ? printf("CObj delete...\n");
? ? }
};
//線程測(cè)試類
class CTestThread : public TTThread
{
public:
? ? virtual unsigned Process()
? ? {
? ? ? ?return 0;
? ? }
};

線程函數(shù)返回

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

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

測(cè)試代碼:

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

測(cè)試結(jié)果:

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

TerminateThread函數(shù)

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

BOOL TerminateThread( 
  HANDLE hThread, 
  DWORD dwExitCode); 

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

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

用TerminateThread銷毀線程示例代碼:

// 在另一個(gè)線程中進(jìn)行調(diào)用,這里是在主線程終止測(cè)試線程
void TTThread::Destory()
{
    if (m_hThread)
    {
        //TerminateThread以異步方式執(zhí)行,函數(shù)返回不代表線程結(jié)束,
        //線程函數(shù)停止執(zhí)行,位置隨機(jī),類對(duì)象不會(huì)被析構(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)用程序從來(lái)不使用這個(gè)函數(shù),因?yàn)楸唤K止運(yùn)行的線程收不到它被撤消的通知。并且,如果使用TerminateThread,那么在擁有線程的進(jìn)程終止運(yùn)行之前,系統(tǒng)不撤消該線程的堆棧,造成內(nèi)存不能及時(shí)釋放。

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

測(cè)試結(jié)果

main thread begin...
CObj create...
current index:0
current index:1
end destroy
main thread end...
//CObj沒(méi)有執(zhí)行析構(gòu)函數(shù),沒(méi)有及時(shí)釋放線程申請(qǐng)的_tiddata內(nèi)存
請(qǐng)按任意鍵繼續(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++類對(duì)象)將不被析構(gòu)。由于這個(gè)原因,最好從線程函數(shù)返回,而不是通過(guò)調(diào)用ExitThread來(lái)返回。
當(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用來(lái)撤消線程的函數(shù)。如果編寫C/C++代碼,那么決不應(yīng)該調(diào)用ExitThread。應(yīng)該使用Visual C++運(yùn)行期庫(kù)函數(shù)_endthreadex,因?yàn)開(kāi)endthreadex可以確保,及時(shí)釋放線程申請(qǐng)的tiddata內(nèi)存。

測(cè)試代碼

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;
}

測(cè)試結(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...
請(qǐng)按任意鍵繼續(xù). . .

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

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

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

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

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

BOOL GetExitCodeThread( 
  HANDLE hThread, 
  PDWORD pdwExitCode); 

退出代碼的值在pdwExitCode指向的DWORD中返回。如果調(diào)用GetExitCodeThread時(shí)線程尚未終止運(yùn)行,該函數(shù)就用STILL_ACTIVE標(biāo)識(shí)符(定義為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ī),類對(duì)象不會(huì)被析構(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

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

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

相關(guān)文章

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

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

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

    C語(yǔ)言自定義類型全解析

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

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

    動(dòng)態(tài)內(nèi)存是相對(duì)靜態(tài)內(nèi)存而言的。所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語(yǔ)言中動(dòng)態(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語(yǔ)言實(shí)現(xiàn)BMP圖像的讀寫功能

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

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

    Linux中利用c語(yǔ)言刪除某個(gè)目錄下的文件

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

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

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

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

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

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

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

最新評(píng)論