日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

一种不会导致资源泄露的“终止”线程的方法

發布時間:2023/11/27 生活经验 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一种不会导致资源泄露的“终止”线程的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 在項目工程中,我們可能會使用第三方開發的模塊。該模塊提供一個接口用于完成非常復雜和耗時的工作。我們一般不會將該API放在UI線程中執行,而是啟動一個線程,用工作線程去執行這個耗時的操作。(轉載請指明出于breaksoftware的csdn博客)

static VOID OtherPartFun() // 第三方提供函數,超級耗時,不如來個極限,死循環
{int nIndex = 0;while ( true ) {nIndex++;printf("%d\n",nIndex);Sleep( ONESECOND );}
}
// 我們啟動的線程函數,用于在工作線程中執行那個耗時的第三方提供函數
static DWORD WINAPI ThreadRoutine(LPVOID lpParam)
{OtherPartFun();return 0;
}

? ? ? ? 以上方法很好解決了不堵塞關鍵線程的目的。但是問題永遠不會間斷。比如當我們在某些條件下,我們要終止該線程的執行。如何做呢?

? ? ? ? 一是讓該模塊設計方提供一個終止線程接口,比如給我們一個事件,我們通過設置這個事件來通知該線程退出。

static VOID OtherPartFun()
{int nIndex = 0;while ( WAIT_OBJECT_0 != WaitForSingleObject( g_ExitEvent, 1000)  ) {nIndex++;printf("%d\n",nIndex);Sleep( ONESECOND );}
}

? ? ? ? 另一種可能就是TerminateThread。

? ? ? ? 如果方案1對方不提供, 你也無法接受方案二導致的資源未釋放。那有如何辦呢?

? ? ? ? 目前有個方案是使用SEH。我們刻意造成該線程產生異常,同時在函數中捕獲該異常,以使得線程可以體面的退出。

? ? ? ? 以下我詳細講解下這個方案。

? ? ? ? 1 線程函數加上SEH捕獲異常。這樣我們認為制造異常后,不會導致進程出問題。

static DWORD WINAPI ThreadRoutine(LPVOID lpParam)
{__try {OtherPartFun();  // 第三方的耗時函數,我們用__try包住它。}__except(EXCEPTION_EXECUTE_HANDLER) {printf("Except!Thread will exit.\n"); // 我們認為觸發異常后會進入該邏輯。}return 0;
}

? ? ? ? 2 設置異常。我們設置異常的大體思路是

? ? ? ? A 掛起線程

? ? ? ? ?B 獲取線程EIP

? ? ? ? ?C 修改線程EIP為違例地址

? ? ? ? ?D 恢復線程

? ? ? ? ?我們看下代碼

    HANDLE hThread = NULL;hThread = CreateThread( NULL, 0, ThreadRoutine, NULL, 0, NULL ); // 創建線程Sleep( 2 * ONESECOND ); // 模擬做點事情SuspendThread(hThread); // 掛起線程CONTEXT ThreadContext;ThreadContext.ContextFlags = CONTEXT_CONTROL; // 設置要獲取EIP寄存器GetThreadContext( hThread, &ThreadContext );  // 獲取EIP寄存器 ThreadContext.Eip = NULL;                     // 將EIP寄存器改成違例地址,這樣在恢復線程執行后,線程會適時拋出異常SetThreadContext(hThread , &ThreadContext);   // 保存EIPResumeThread(hThread);                        // 恢復線程,線程即將退出Sleep( 15 * ONESECOND );if ( NULL != hThread ) {CloseHandle(hThread);hThread = NULL;}

? ? ? ? 我們看下執行結果


? ? ? ? 可以發現,我們線程“體面”的退出了。

? ? ? ? 其實這個方案也是存在不完善的地方的。比如我們線程產生了死鎖等,線程將進入內核態等待。這個時候我們獲取的EIP是客戶態函數的著陸點。而我們此時去修改EIP,還是要等待線程從內核態返回后才能觸發異常。

? ? ? ? 提供下該例子的工程

總結

以上是生活随笔為你收集整理的一种不会导致资源泄露的“终止”线程的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。