{"id":41403,"date":"2003-12-22T09:59:00","date_gmt":"2003-12-22T09:59:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2003\/12\/22\/how-do-i-determine-whether-i-own-a-critical-section-if-i-am-not-supposed-to-look-at-internal-fields\/"},"modified":"2003-12-22T09:59:00","modified_gmt":"2003-12-22T09:59:00","slug":"how-do-i-determine-whether-i-own-a-critical-section-if-i-am-not-supposed-to-look-at-internal-fields","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20031222-00\/?p=41403","title":{"rendered":"How do I determine whether I own a critical section if I am not supposed to look at internal fields?"},"content":{"rendered":"<p><a href=\"http:\/\/weblogs.asp.net\/oldnewthing\/posts\/44425.aspx#44659\">Seth asks<\/a> how he can perform proper exception-handling cleanup if he doesn&#8217;t know whether he needs to clean up a critical section. <\/p>\n<blockquote class=\"q\"><p>I&#8217;m using SEH, and have some __try\/__except blocks in which the code enters and leaves critical sections. If an exception occurs, I don&#8217;t know if I&#8217;m currently in the CS or not. Even wrapping the code in __try\/__finally wouldn&#8217;t solve my problems. <\/p><\/blockquote>\n<p>Answer: You know whether you own the CRITICAL_SECTION because you entered it. <\/p>\n<dl>\n<dt>Method 1: Deduce it from your instruction pointer.<\/p>\n<dd>&#8220;If I&#8217;m at this line of code, then I must be in the critical section.&#8221; <\/p>\n<pre>__try {\n  ...\n  EnterCriticalSection(x);\n  __try { \/\/ if an exception happens here\n     ...  \/\/ make sure we leave the CS\n  } __finally { LeaveCriticalSection(x); }\n  ...\n} except (filter) {\n  ...\n}\n<\/pre>\n<p>Note that this technique is robust to nested calls to EnterCriticalSection. If you take the critical section again, then wrap the nested call in its own try\/finally. <\/p>\n<dt>Method 2: Deduce it from local state<\/p>\n<dd>&#8220;I&#8217;ll remember whether I entered the critical section.&#8221; <\/p>\n<pre>int cEntered = 0;\n__try {\n  ...\n  EnterCriticalSection(x);\n  cEntered++;\n  ...\n  cEntered--;\n  LeaveCriticalSection(x);\n  ...\n} except (filter) {\n  while (cEntered--)\n    LeaveCriticalSection(x);\n  ...\n}\n<\/pre>\n<p>Note that this technique is also robust to nested calls to EnterCriticalSection. If you take the critical section again, increment cEntered another time. <\/p>\n<dt>Method 3: Track it in an object<\/p>\n<dd>Wrap the CRITICAL_SECTION in another object.<\/p>\n<p>This most closely matches what Seth is doing today. <\/p>\n<pre>class CritSec : CRITICAL_SECTION\n{\npublic:\n CritSec() : m_dwDepth(0), m_dwOwner(0)\n   { InitializeCriticalSection(this); }\n ~CritSec() { DeleteCriticalSection(this); }\n void Enter() { EnterCriticalSection(this);\n    m_dwDepth++;\n    m_dwOwner = GetCurrentThreadId(); }\n void Leave() { if (!--m_dwDepth) m_dwOwner=0;\n    LeaveCriticalSection(this); }\n bool Owned()\n   { return GetCurrentThreadId() == m_dwOwner; }\nprivate:\n  DWORD m_dwOwner;\n  DWORD m_dwDepth;\n};\n__try {\n  assert(!cs.Owned());\n  ...\n  cs.Enter();\n  ...\n  cs.Leave();\n  ...\n} except (filter) {\n  if (cs.Owned()) cs.Leave();\n}\n<\/pre>\n<p>Notice that this code is <b>not<\/b> robust to nested critical sections (and correspondingly, Seth&#8217;s code isn&#8217;t either). If you take the critical section twice, the exception handler will only leave it once. <\/p>\n<p>Note also that we assert that the critical section is not initially owned. If it happens to be owned already, then our cleanup code may attempt to leave a critical section that it did not enter. (Imagine if an exception occurs during the first &#8220;&#8230;&#8221;.) <\/p>\n<dt>Method 4: Track it in a smarter object<\/p>\n<dd>Wrap the CRITICAL_SECTION in a smarter object.<\/p>\n<p>Add the following method to the CritSec object above:<\/p>\n<p><pre> DWORD Depth() { return Owned() ? m_dwDepth : 0; }\n<\/pre>\n<\/p>\n<p>Now you can be robust to nested critical sections: <\/p>\n<pre>DWORD dwDepth = cs.Depth();\n__try {\n  ...\n  cs.Enter();\n  ...\n  cs.Leave();\n  ...\n} except (filter) {\n  while (cs.Depth() &gt; dwDepth)\n    cs.Leave();\n}\n<\/pre>\n<\/dd>\n<\/dl>\n<p>Note however that I am dubious of the entire endeavor that inspired the original question. <\/p>\n<p>Cleaning up behind an exception thrown from within a critical section raises the issue of &#8220;How do you know what is safe to clean up?&#8221; You have a critical section because you are about to destabilize a data structure and you don&#8217;t want others to see the data structure while it is unstable. But if you take an exception while owning the critical section &#8211; well your data structures are unstable at the point of the exception. Merely leaving the critical section will now leave your data structures in an inconsistent state, leading to harder-to-diagnose bugs later on. &#8220;How did my count get out of sync?&#8221; <\/p>\n<p>More rants on exceptions in a future entry. <\/p>\n<p><b>Exercise<\/b>: Why don&#8217;t we need to use synchronization to protect the uses of m_dwDepth and m_dwOwner? <\/p>\n<p>\n<b>Update 2004\/Jan\/16<\/b>: Seth pointed out that I got the two branches of the ternary operator backwards in the Depth() function. Fixed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Seth asks how he can perform proper exception-handling cleanup if he doesn&#8217;t know whether he needs to clean up a critical section. I&#8217;m using SEH, and have some __try\/__except blocks in which the code enters and leaves critical sections. If an exception occurs, I don&#8217;t know if I&#8217;m currently in the CS or not. Even [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-41403","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Seth asks how he can perform proper exception-handling cleanup if he doesn&#8217;t know whether he needs to clean up a critical section. I&#8217;m using SEH, and have some __try\/__except blocks in which the code enters and leaves critical sections. If an exception occurs, I don&#8217;t know if I&#8217;m currently in the CS or not. Even [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41403","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=41403"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41403\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=41403"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=41403"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=41403"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}