锘??xml version="1.0" encoding="utf-8" standalone="yes"?>91精品国产综合久久四虎久久无码一级 ,久久99国产精品99久久,久久免费精品视频http://m.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://m.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://m.shnenglu.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.htmlhttp://m.shnenglu.com/flagman/comments/161934.htmlhttp://m.shnenglu.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html#Feedback0http://m.shnenglu.com/flagman/comments/commentRss/161934.htmlhttp://m.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://m.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.htmlflagmanflagmanTue, 08 Feb 2011 12:57:00 GMThttp://m.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.htmlhttp://m.shnenglu.com/flagman/comments/139812.htmlhttp://m.shnenglu.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html#Feedback0http://m.shnenglu.com/flagman/comments/commentRss/139812.htmlhttp://m.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 鍙戣〃璇勮
]]>
久久精品毛片免费观看| 国产精品一区二区久久| 亚洲国产视频久久| 亚洲中文字幕无码久久综合网 | 色综合久久久久网| 亚洲精品高清国产一久久| 日韩十八禁一区二区久久| 99久久国产综合精品女同图片| 午夜天堂精品久久久久| 青青草原综合久久| 久久综合久久综合亚洲| 国产一级做a爰片久久毛片| 亚洲国产成人精品91久久久 | 精品久久久久久久无码| 久久亚洲av无码精品浪潮| 久久人人爽人人爽人人片av高请| 久久精品国产精品青草app| 亚洲午夜精品久久久久久浪潮 | 久久精品国产亚洲AV香蕉| 久久亚洲国产精品123区| 国产产无码乱码精品久久鸭| 久久久精品国产亚洲成人满18免费网站| 97久久精品人人澡人人爽| 一级a性色生活片久久无| 久久久久久久久66精品片| 久久精品亚洲男人的天堂| 性做久久久久久久| 漂亮人妻被中出中文字幕久久| 久久久久亚洲AV无码专区桃色| 国产精品久久久久久福利69堂| 亚洲va久久久噜噜噜久久狠狠| 一极黄色视频久久网站| 久久久久久综合一区中文字幕| 国产亚洲精久久久久久无码| 一本久久知道综合久久| 亚洲日韩欧美一区久久久久我| 精品久久久久久久久久久久久久久| 99久久免费国产特黄| 久久er99热精品一区二区| 久久精品毛片免费观看| 高清免费久久午夜精品|