关于《Windows程序设计(第2版)王艳平 张铮编著》第3章设计TLS里的一个问题
生活随笔
收集整理的這篇文章主要介紹了
关于《Windows程序设计(第2版)王艳平 张铮编著》第3章设计TLS里的一个问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
如摘要所述,經過斷點后發現如下代碼有問題:
CNoTrackObject* CThreadLocalObject::GetData(CNoTrackObject* (*pfnCreateObject)()) {if (m_nSlot == 0) {if (_afxThreadData == nullptr) {_afxThreadData = new (__afxThreadData) CThreadSlotData;//OutputDebugString(_T("New CThreadSlotData\n"));}m_nSlot = _afxThreadData->AllocSlot();}// ... }這里面_afxThreadData的new執行了多次,很明顯是由于多個線程在上一行if判斷_afxThreadData為nullptr后即被掛起,之后被調度執行時,出現這種情形:一個線程的AllocSlot已經調用過了,另一個線程跑過來將_afxThreadData又new了一遍,抹掉了之前AllocSlot里面做的各種關鍵操作,狀態徹底混亂了。 于是,我嘗試在afxtls.cpp里寫了下面一個類來做這里的new操作:
class CTlsInitializer { public:CTlsInitializer() {if (_afxThreadData == nullptr) {_afxThreadData = new (__afxThreadData) CThreadSlotData;}} }; CTlsInitializer gInitializer;實踐證明結果正確了,之后無論怎么運行程序都是正確的結果,release和debug都不崩潰。 后來想了想,其實只要這段new能無競爭的跑一遍,以后就不會有問題了,像上面單獨弄一個CTlsInitializer gInitializer;雖然也可以,但其實只要在主線程里調用一下CThreadLocal的GetData函數,即可達到同樣的目的。
CThreadLocal<MyThreadData1> g_myThreadData1; CThreadLocal<MyThreadData2> g_myThreadData2; // ... int main() {//g_myThreadData1.operator->();(MyThreadData1*)g_myThreadData1; // 與上一行等價. 不用所有的CThreadLocal對象都做這個操作,只要任意一個即可。return 0; }運行效果和上面一樣,也是正確的。不過從實用的角度,還是CTlsInitializer gInitializer;為好。
轉載于:https://my.oschina.net/zhoubaojing/blog/715526
總結
以上是生活随笔為你收集整理的关于《Windows程序设计(第2版)王艳平 张铮编著》第3章设计TLS里的一个问题的全部內容,希望文章能夠幫你解決所遇到的問題。