﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-提琴协奏-随笔分类-并发和并行 concurrency &amp; parallelism</title><link>http://www.cppblog.com/flagman/category/15722.html</link><description> 唐亮的个人技术博客
【欢迎转载，但请标明原作者】</description><language>zh-cn</language><lastBuildDate>Mon, 12 Dec 2011 16:19:20 GMT</lastBuildDate><pubDate>Mon, 12 Dec 2011 16:19:20 GMT</pubDate><ttl>60</ttl><item><title>C++ library series -- in the MFC multiple-thread environment, how to quit worker-thread safely which begins with AfxBeginThread</title><link>http://www.cppblog.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html</link><dc:creator>flagman</dc:creator><author>flagman</author><pubDate>Sun, 11 Dec 2011 12:35:00 GMT</pubDate><guid>http://www.cppblog.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html</guid><wfw:comment>http://www.cppblog.com/flagman/comments/161934.html</wfw:comment><comments>http://www.cppblog.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flagman/comments/commentRss/161934.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flagman/services/trackbacks/161934.html</trackback:ping><description><![CDATA[<div><div>&nbsp; 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.</div><div>&nbsp; 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.</div><div>&nbsp; Consequently, serious developer should prepare for such case (other worker thread quits before main thread).</div><div>&nbsp;&nbsp;</div><div>&nbsp; The reasonable resolve for such issue, would ensure any other threads should quit before the main thread.&nbsp;</div><div>&nbsp;&nbsp;</div><div>.h file&nbsp;</div><div>&nbsp; /////////////////////////////////////////////////////////////////////////////</div><div>// CSafeEnterLeaveThread thread</div><div></div><div>class CSafeEnterLeaveThread : public CWinThread</div><div>{</div><div><span style="white-space:pre">	</span>DECLARE_DYNCREATE(CSafeEnterLeaveThread)</div><div>protected:</div><div><span style="white-space:pre">	</span>CSafeEnterLeaveThread(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // protected constructor used by dynamic creation</div><div></div><div>// Attributes</div><div>public:</div><div></div><div>// Operations</div><div>public:</div><div></div><div>// Overrides</div><div><span style="white-space:pre">	</span>// ClassWizard generated virtual function overrides</div><div><span style="white-space:pre">	</span>//{{AFX_VIRTUAL(CSafeEnterLeaveThread)</div><div><span style="white-space:pre">	</span>public:</div><div><span style="white-space:pre">	</span>virtual BOOL InitInstance();</div><div><span style="white-space:pre">	</span>virtual int ExitInstance();</div><div><span style="white-space:pre">	</span>//}}AFX_VIRTUAL</div><div></div><div>// Implementation</div><div>protected:</div><div><span style="white-space:pre">	</span>virtual ~CSafeEnterLeaveThread();</div><div></div><div><span style="white-space:pre">	</span>// Generated message map functions</div><div><span style="white-space:pre">	</span>//{{AFX_MSG(CSafeEnterLeaveThread)</div><div><span style="white-space:pre">		</span>// NOTE - the ClassWizard will add and remove member functions here.</div><div><span style="white-space:pre">	</span>//}}AFX_MSG</div><div></div><div><span style="white-space:pre">	</span>DECLARE_MESSAGE_MAP()</div><div>};</div><div></div><div>.cpp file&nbsp;</div><div>/////////////////////////////////////////////////////////////////////////////</div><div>// CSafeEnterLeaveThread</div><div></div><div>IMPLEMENT_DYNCREATE(CSafeEnterLeaveThread, CWinThread)</div><div></div><div>CSafeEnterLeaveThread::CSafeEnterLeaveThread()</div><div>{</div><div>}</div><div></div><div>CSafeEnterLeaveThread::~CSafeEnterLeaveThread()</div><div>{</div><div>}</div><div></div><div>BOOL CSafeEnterLeaveThread::InitInstance()</div><div>{</div><div><span style="white-space:pre">	</span>// TODO: &nbsp;perform and per-thread initialization here</div><div><span style="white-space:pre">	</span>ASSERT(this-&gt;m_hThread);</div><div><span style="white-space:pre">	</span>CMainApp::RegisterMFCThread(this-&gt;m_hThread);</div><div><span style="white-space:pre">	</span>return TRUE;</div><div>}</div><div></div><div>int CSafeEnterLeaveThread::ExitInstance()</div><div>{</div><div><span style="white-space:pre">	</span>// TODO: &nbsp;perform any per-thread cleanup here</div><div><span style="white-space:pre">	</span>ASSERT(this-&gt;m_hThread);</div><div><span style="white-space:pre">	</span>CMainApp::UnRegisterMFCThread(this-&gt;m_hThread);</div><div><span style="white-space:pre">	</span>return CWinThread::ExitInstance();</div><div>}</div><div></div><div>BEGIN_MESSAGE_MAP(CSafeEnterLeaveThread, CWinThread)</div><div><span style="white-space:pre">	</span>//{{AFX_MSG_MAP(CSafeEnterLeaveThread)</div><div><span style="white-space:pre">		</span>// NOTE - the ClassWizard will add and remove mapping macros here.</div><div><span style="white-space:pre">	</span>//}}AFX_MSG_MAP</div><div>END_MESSAGE_MAP()</div><div></div><div></div><div></div><div>And in the CMainApp,</div><div></div><div></div><div>set&lt;HANDLE&gt; g_ThreadHandleSet;</div><div>HANDLE g_ThreadHandleArray[MAXIMUM_WAIT_OBJECTS];</div><div>CCriticalSection g_csGlobalData;</div><div></div><div>void CAccgbApp::CheckAllOtherMFCThreadsLeave()</div><div>{</div><div><span style="white-space:pre">	</span>int count = g_ThreadHandleSet.size();</div><div><span style="white-space:pre">	</span>if (count == 0) return;</div><div><span style="white-space:pre">	</span>set&lt;HANDLE&gt;::iterator it;</div><div><span style="white-space:pre">	</span>int idx = 0;</div><div><span style="white-space:pre">	</span>for (it = g_ThreadHandleSet.begin(); it != g_ThreadHandleSet.end() &amp;&amp; idx &lt; MAXIMUM_WAIT_OBJECTS; it++, idx++)</div><div><span style="white-space:pre">	</span>{</div><div><span style="white-space:pre">		</span>g_ThreadHandleArray[idx] = *it;</div><div><span style="white-space:pre">	</span>}</div><div><span style="white-space:pre">	</span>if (count &gt; idx) count = idx;</div><div></div><div><span style="white-space:pre">	</span>::WaitForMultipleObjects(count, g_ThreadHandleArray, TRUE, INFINITE);</div><div>}</div><div></div><div>void CAccgbApp::CleanupGlobalData()</div><div>{</div><div><span style="white-space:pre">	</span>g_csGlobalData.Lock();</div><div><span style="white-space:pre">	</span>g_ThreadHandleSet.empty();</div><div><span style="white-space:pre">	</span>g_csGlobalData.Unlock();</div><div>}</div><div></div><div>BOOL CAccgbApp::RegisterMFCThread(HANDLE hThread)</div><div>{</div><div><span style="white-space:pre">	</span>if (hThread == NULL) return FALSE;</div><div><span style="white-space:pre">	</span></div><div><span style="white-space:pre">	</span>g_csGlobalData.Lock();</div><div><span style="white-space:pre">	</span>if (g_ThreadHandleSet.find(hThread) == g_ThreadHandleSet.end())&nbsp;</div><div><span style="white-space:pre">		</span>g_ThreadHandleSet.insert(hThread);</div><div><span style="white-space:pre">	</span>g_csGlobalData.Unlock();</div><div></div><div><span style="white-space:pre">	</span>return TRUE;</div><div>}</div><div></div><div>void CAccgbApp::UnRegisterMFCThread(HANDLE hThread)</div><div>{</div><div><span style="white-space:pre">	</span>if (hThread == NULL) return;</div><div></div><div><span style="white-space:pre">	</span>g_csGlobalData.Lock();</div><div><span style="white-space:pre">	</span>if (g_ThreadHandleSet.find(hThread) != g_ThreadHandleSet.end())</div><div><span style="white-space:pre">		</span>g_ThreadHandleSet.erase(hThread);</div><div><span style="white-space:pre">	</span>g_csGlobalData.Unlock();</div><div>}</div></div><img src ="http://www.cppblog.com/flagman/aggbug/161934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flagman/" target="_blank">flagman</a> 2011-12-11 20:35 <a href="http://www.cppblog.com/flagman/archive/2011/12/11/how_to_quit_worker-thread_safely_which_begins_with_AfxBeginThread.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ library系列 -- static destructors in multiple threads</title><link>http://www.cppblog.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html</link><dc:creator>flagman</dc:creator><author>flagman</author><pubDate>Tue, 08 Feb 2011 12:57:00 GMT</pubDate><guid>http://www.cppblog.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html</guid><wfw:comment>http://www.cppblog.com/flagman/comments/139812.html</wfw:comment><comments>http://www.cppblog.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flagman/comments/commentRss/139812.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flagman/services/trackbacks/139812.html</trackback:ping><description><![CDATA[<p>&nbsp; In VC++ 8.0, while&nbsp; code compiled with /clr or /clr:pure, static destructors sometimes would not being properly called before process exites in multiple threads.</p>
<p>&nbsp; CRT incorrectly set a lock at _global_unlock which resulted in such issue.</p>
<p>&nbsp; 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.</p>
<p>&nbsp; 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.</p>
<p>&nbsp; __onexitbegin_m and __onexitend_m were shared by the different threads; It's the key point of such issue. For example, the following statements,</p>
<p>&nbsp; __onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);<br>&nbsp; __onexitend_m = (_CPVFV *)_encode_pointer(onexitend_m);</p>
<p>should also guarded by __global_lock() and __global_unlock() or other syn primitives.</p>
<p><br>__global_lock();<br>__onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);<br>__onexitend_m&nbsp;&nbsp; = (_CPVFV *)_encode_pointer(onexitend_m);<br>__global_unlock();</p>
<p><br>extern "C" int __clrcall _atexit_m(_CPVFV func)<br>{<br>&nbsp;MANAGED_ASSERT(AppDomain::CurrentDomain-&gt;IsDefaultAppDomain(), "This fuction must be called in the default domain");</p>
<p>&nbsp;__global_lock();<br>&nbsp;_CPVFV* onexitbegin_m = (_CPVFV*)_decode_pointer(__onexitbegin_m);<br>&nbsp;_CPVFV* onexitend_m = (_CPVFV*)_decode_pointer(__onexitend_m);<br>&nbsp;__global_unlock();</p>
<p>&nbsp;int retval = _atexit_helper((_CPVFV)_encode_pointer(func), &amp;__exit_list_size, &amp;onexitend_m, &amp;onexitbegin_m);</p>
<p>&nbsp;__global_lock();<br>&nbsp;__onexitbegin_m = (_CPVFV*)_encode_pointer(onexitbegin_m);<br>&nbsp;__onexitend_m&nbsp; = (_CPVFV*)_encode_pointer(onexitend_m);<br>&nbsp;__global_unlock();</p>
<p>&nbsp;return retval;<br>}</p>
<img src ="http://www.cppblog.com/flagman/aggbug/139812.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flagman/" target="_blank">flagman</a> 2011-02-08 20:57 <a href="http://www.cppblog.com/flagman/archive/2011/02/08/static_destructors_in_multiple_threads.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>