執行緒自我終止會導致執行緒內部物件的析構異常?

2021-03-31 08:56:58 字數 2322 閱讀 9970

一開始主線程a是作為乙個對話方塊ctestdlg存在,現在,在ctestdlg的成員函式onstartthread中開始乙個新執行緒b,onstartthread函式中cstring區域性變數stra(注1)作為執行緒b工作函式的引數pparam,ctestdlg的成員函式onendthread用於設定中止執行緒b,見下面的示例**1

... 執行緒a(主線程)

ctestdlg::onstartthread()

void cmsitestdlg::onendthread()

... 執行緒b

uint threadproc(lpvoid pparam)

sleep(200); // 模擬線程工作

}return 0; //正常返回0

}在這裡,執行緒a與執行緒b的執行是非同步的,即執行緒a無需等待執行緒b的完成,啟動執行緒b後,先進入執行緒b的工作函式:

struct cstringdata};

// cleanup ole if required

if (pthread->m_lpfnoletermorfreelib != null)

(*pthread->m_lpfnoletermorfreelib)(true, false);

if (bdelete)

pthread->delete();

pstate->m_pcurrentwinthread = null;}

// allow cleanup of any thread local objects

afxtermthread();

// allow c-runtime to cleanup, and exit the thread

_endthreadex(nexitcode);

#endif //!_mt

}afxendthread通過呼叫pthread->delete()會使執行緒b的棧清空(開始執行緒b時就已為執行緒b分配了棧:參考3),然後將執行緒b工作函式中已為所有變數分配的棧全部清空,包括strb,但是這不會使strb得以正常析構,也就無法將堆資料的引用計數減1,並最終不會釋放堆資料,引發了記憶體洩漏!

針對此,我另做了乙個測試,並證明了strb確實未被正常析構,見下面的示例**2:

... 執行緒a(主線程)

ctestdlg::onstartthread()

void cmsitestdlg::onendthread()

... 執行緒b

uint threadproc(lpvoid pparam)

g_bstopthread = true; //只進入一次, 下一次就終止自已

sleep(200); // 模擬線程工作

}return 0; //正常返回0

}比之示例1**,加了兩行**(粗體顯示)。

g_bstopthread = true,使執行緒b立刻在下一次迴圈時結束;

waitforsingleobject(m_pthread->m_hthread, infinite),等待

至於為什麼執行緒自我終止不能使執行緒內部物件正常析構,我需要進一步查閱相關資料,以後將會彌補。

2003.11.9 14:21

我同意某位仁兄的看法,堆就是堆,棧就是棧。

國內很多寫書或譯書的把堆(heap)寫成堆疊,把棧(stack)也寫成堆疊。事實上兩者是不同的。

樓主寫的是棧(stack).棧就是執行緒一開始作業系統分配給這個執行緒的一塊記憶體(樓主已經講的很詳細了)。當你某個函式的區域性變數很大比如接近1m,棧(stack)就會溢位。

堆正如mayax所說的那樣,分預設堆和輔助堆,在c++,c中使用delete,new,malloc、free 來操作預設堆(預設大小為1mb)。堆是不會溢位的。只有分配失敗。比如 pvoid pv = malloc(0x100000);當malloc看到預設堆中沒有這麼大的記憶體就會返回null,這就是分配失敗。當然預設堆不夠用了的話,在 win32中你可以用heapcreate來建立乙個輔助堆,用heapalloc來分配堆記憶體,用heapfree來釋放堆記憶體,用 heapdestroy來銷毀這個輔助堆。

建議對這個東西還弄不懂的多看看jeffrey richter的《windows核心程式設計》,這裡面把win32的記憶體管理講的很清楚,不過這本書的中譯者還是把stack翻譯成堆疊,把heap也翻譯成堆疊。

另外值得一提的是全域性變數不是放在堆裡面而是放在pe檔案的資料節(section),當作業系統裝載程式的時候把pe檔案的資料節對映到**,全域性變數就在那塊記憶體裡面。這個大家可以了解一下pe結構。

多執行緒全域性物件析構導致執行緒執行出錯

這樣的問題應該大多出現在大的程式裡面,出現這樣問題一般具備幾個條件 1 全域性物件太多 2 多執行緒 3 執行緒很多,主程序沒有等待執行緒結束 4 主程序由於某種原因終止 原因分析 首先全域性物件太多,主程序結束時需要一定的時間析構各全域性物件 此時,先析構的全域性物件由於主程序忙著析構其他的全域性...

面試題之使用無界佇列的執行緒池會導致記憶體飆公升嗎?

答案 會 分析 建立執行緒池方式有如下幾種 executors.newfixedthreadpool 10 linkedblockingqueue 無限加入佇列 executors.newscheduledthreadpool 10 delayedworkqueue 佇列如果滿了,阻塞 execut...

面試題之使用無界佇列的執行緒池會導致記憶體飆公升嗎?

答案 會 分析 建立執行緒池方式有如下幾種 executors.newfixedthreadpool 10 linkedblockingqueue 無限加入佇列 executors.newscheduledthreadpool 10 delayedworkqueue 佇列如果滿了,阻塞 execut...