锘??xml version="1.0" encoding="utf-8" standalone="yes"?>91精品国产综合久久四虎久久无码一级 ,久久99国产精品99久久,久久免费精品视频http://www.shnenglu.com/flagman/category/15722.html 鍞愪寒鐨勪釜浜烘妧鏈崥瀹? 銆愭榪庤漿杞斤紝浣嗚鏍囨槑鍘熶綔鑰呫?/description>zh-cnMon, 12 Dec 2011 16:19:20 GMTMon, 12 Dec 2011 16:19:20 GMT60C++ library series -- in the MFC multiple-thread environment, how to quit worker-thread safely which begins with AfxBeginThreadhttp://www.shnenglu.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.htmlflagmanflagmanSun, 11 Dec 2011 12:35:00 GMThttp://www.shnenglu.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.htmlhttp://www.shnenglu.com/flagman/comments/161934.htmlhttp://www.shnenglu.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html#Feedback0http://www.shnenglu.com/flagman/comments/commentRss/161934.htmlhttp://www.shnenglu.com/flagman/services/trackbacks/161934.html
  In the MFC environment, normally, thread should be launched with AfxBeginThread for taking usage of MFC multiple-thread mechanism; In such mechanism, those datastructures, such as AFX_MODULE_STATE, would be used by MFC framework to maintain related thread information. It runs well when threads, launched with AfxBeginThread, quit before the main thread, which is responsible for initializing C run-time, but if such main thread quit before any other thread launched by AfxBeginThread, the current application would crash.
  Such crash comes from the _afxThreadData (CThreadSlotData* _afxThreadData, which is defined in AFXTLS.cpp as global data structure) has been destructed while the main thread quits and it will invoke related function to clean up global data structures, including _afxThreadData definitely.
  Consequently, serious developer should prepare for such case (other worker thread quits before main thread).
  
  The reasonable resolve for such issue, would ensure any other threads should quit before the main thread. 
  
.h file 
  /////////////////////////////////////////////////////////////////////////////
// CSafeEnterLeaveThread thread
class CSafeEnterLeaveThread : public CWinThread
{
DECLARE_DYNCREATE(CSafeEnterLeaveThread)
protected:
CSafeEnterLeaveThread();           // protected constructor used by dynamic creation
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSafeEnterLeaveThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
// Implementation
protected:
virtual ~CSafeEnterLeaveThread();
// Generated message map functions
//{{AFX_MSG(CSafeEnterLeaveThread)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
.cpp file 
/////////////////////////////////////////////////////////////////////////////
// CSafeEnterLeaveThread
IMPLEMENT_DYNCREATE(CSafeEnterLeaveThread, CWinThread)
CSafeEnterLeaveThread::CSafeEnterLeaveThread()
{
}
CSafeEnterLeaveThread::~CSafeEnterLeaveThread()
{
}
BOOL CSafeEnterLeaveThread::InitInstance()
{
// TODO:  perform and per-thread initialization here
ASSERT(this->m_hThread);
CMainApp::RegisterMFCThread(this->m_hThread);
return TRUE;
}
int CSafeEnterLeaveThread::ExitInstance()
{
// TODO:  perform any per-thread cleanup here
ASSERT(this->m_hThread);
CMainApp::UnRegisterMFCThread(this->m_hThread);
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(CSafeEnterLeaveThread, CWinThread)
//{{AFX_MSG_MAP(CSafeEnterLeaveThread)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
And in the CMainApp,
set<HANDLE> g_ThreadHandleSet;
HANDLE g_ThreadHandleArray[MAXIMUM_WAIT_OBJECTS];
CCriticalSection g_csGlobalData;
void CAccgbApp::CheckAllOtherMFCThreadsLeave()
{
int count = g_ThreadHandleSet.size();
if (count == 0) return;
set<HANDLE>::iterator it;
int idx = 0;
for (it = g_ThreadHandleSet.begin(); it != g_ThreadHandleSet.end() && idx < MAXIMUM_WAIT_OBJECTS; it++, idx++)
{
g_ThreadHandleArray[idx] = *it;
}
if (count > idx) count = idx;
::WaitForMultipleObjects(count, g_ThreadHandleArray, TRUE, INFINITE);
}
void CAccgbApp::CleanupGlobalData()
{
g_csGlobalData.Lock();
g_ThreadHandleSet.empty();
g_csGlobalData.Unlock();
}
BOOL CAccgbApp::RegisterMFCThread(HANDLE hThread)
{
if (hThread == NULL) return FALSE;
g_csGlobalData.Lock();
if (g_ThreadHandleSet.find(hThread) == g_ThreadHandleSet.end()) 
g_ThreadHandleSet.insert(hThread);
g_csGlobalData.Unlock();
return TRUE;
}
void CAccgbApp::UnRegisterMFCThread(HANDLE hThread)
{
if (hThread == NULL) return;
g_csGlobalData.Lock();
if (g_ThreadHandleSet.find(hThread) != g_ThreadHandleSet.end())
g_ThreadHandleSet.erase(hThread);
g_csGlobalData.Unlock();
}


flagman 2011-12-11 20:35 鍙戣〃璇勮
]]>
C++ library緋誨垪 -- static destructors in multiple threadshttp://www.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.htmlflagmanflagmanTue, 08 Feb 2011 12:57:00 GMThttp://www.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.htmlhttp://www.shnenglu.com/flagman/comments/139812.htmlhttp://www.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html#Feedback0http://www.shnenglu.com/flagman/comments/commentRss/139812.htmlhttp://www.shnenglu.com/flagman/services/trackbacks/139812.html  In VC++ 8.0, while  code compiled with /clr or /clr:pure, static destructors sometimes would not being properly called before process exites in multiple threads.

  CRT incorrectly set a lock at _global_unlock which resulted in such issue.

  In CLR-mixed mode, during the inialization of static local object, CRT would call _atexit_m(_CPVFV func) in msilexit.cpp to register a special __clrcall callback function which would be called back to destroy such static object when the current AppDomain quited.

  In the multithread environment, _atexit_helper which was invoked by _atexit_m, could register such callbace function successfully because it had been guarded by __global_lock() and __global_unlock(). But in the same environment, the _atexit_m would fail to assign the correct value to __onexitbegin_m and __onexitend_m.

  __onexitbegin_m and __onexitend_m were shared by the different threads; It's the key point of such issue. For example, the following statements,

  __onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);
  __onexitend_m = (_CPVFV *)_encode_pointer(onexitend_m);

should also guarded by __global_lock() and __global_unlock() or other syn primitives.


__global_lock();
__onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);
__onexitend_m   = (_CPVFV *)_encode_pointer(onexitend_m);
__global_unlock();


extern "C" int __clrcall _atexit_m(_CPVFV func)
{
 MANAGED_ASSERT(AppDomain::CurrentDomain->IsDefaultAppDomain(), "This fuction must be called in the default domain");

 __global_lock();
 _CPVFV* onexitbegin_m = (_CPVFV*)_decode_pointer(__onexitbegin_m);
 _CPVFV* onexitend_m = (_CPVFV*)_decode_pointer(__onexitend_m);
 __global_unlock();

 int retval = _atexit_helper((_CPVFV)_encode_pointer(func), &__exit_list_size, &onexitend_m, &onexitbegin_m);

 __global_lock();
 __onexitbegin_m = (_CPVFV*)_encode_pointer(onexitbegin_m);
 __onexitend_m  = (_CPVFV*)_encode_pointer(onexitend_m);
 __global_unlock();

 return retval;
}



flagman 2011-02-08 20:57 鍙戣〃璇勮
]]>
久久久久久久免费视频| 一本久道久久综合狠狠爱| 久久香综合精品久久伊人| 伊色综合久久之综合久久| 2020最新久久久视精品爱 | 日韩精品久久久久久免费| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲国产成人久久笫一页| 久久久国产精品| 欧洲性大片xxxxx久久久| 天天综合久久一二三区| 久久青青草视频| 99久久夜色精品国产网站| 中文字幕无码精品亚洲资源网久久| 久久夜色精品国产亚洲av| 久久夜色精品国产www| 综合久久一区二区三区 | 草草久久久无码国产专区| 久久夜色tv网站| 国产精品美女久久久久av爽| 久久久久人妻一区精品色| 国产精品久久久久久吹潮| 97久久超碰国产精品旧版| 狠狠色丁香婷婷久久综合不卡| 女人香蕉久久**毛片精品| 久久e热在这里只有国产中文精品99| 久久艹国产| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 中文字幕亚洲综合久久| 亚洲国产成人精品91久久久 | 一本色道久久88—综合亚洲精品| 久久久无码精品亚洲日韩蜜臀浪潮| 久久精品国产秦先生| 久久精品无码av| 无码日韩人妻精品久久蜜桃 | 亚洲人成精品久久久久| 一级做a爰片久久毛片人呢| 亚洲?V乱码久久精品蜜桃| 国产精品久久成人影院| 色偷偷91久久综合噜噜噜噜| 欧美喷潮久久久XXXXx|