{"id":9003,"date":"2011-11-30T07:00:00","date_gmt":"2011-11-30T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/11\/30\/if-you-protect-a-write-with-a-critical-section-you-may-also-want-to-protect-the-read\/"},"modified":"2011-11-30T07:00:00","modified_gmt":"2011-11-30T07:00:00","slug":"if-you-protect-a-write-with-a-critical-section-you-may-also-want-to-protect-the-read","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20111130-00\/?p=9003","title":{"rendered":"If you protect a write with a critical section, you may also want to protect the read"},"content":{"rendered":"<p>\nIt is common to have a critical section which protects against\nconcurrent writes to a variable or collection of variables.\nBut if you protect a write with a critical section,\nyou may also want to protect the read,\nbecause the read might race against the write.\n<\/p>\n<p>\n<a HREF=\"http:\/\/adamrosenfield.com\">\nAdam Rosenfield<\/a>\nshared his experience with this issue\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2009\/12\/23\/9940330.aspx#9940599\">\nin a comment from a few years back<\/a>.\nI&#8217;ll reproduce the example here in part to save you the trouble of clicking,\nbut also to make this entry look longer and consequently make it seem\nlike I&#8217;m actually doing some work (when in fact Adam did nearly all of the\nwork):\n<\/p>\n<pre>\n<i>class X {\n volatile int mState;\n CRITICAL_SECTION mCrit;\n HANDLE mEvent;\n};\nX::Wait() {\n while(mState != kDone) {\n   WaitForSingleObject(mEvent, INFINITE);\n }\n}\nX::~X() {\n DestroyCriticalSection(&amp;mCrit);\n}\nX::SetState(int state) {\n EnterCriticalSection(&amp;mCrit);\n \/\/ do some state logic\n mState = state;\n SetEvent(mEvent);\n LeaveCriticalSection(&amp;mCrit);\n}\nThread1()\n{\n X x;\n ... spawn off thread 2 ...\n x.Wait();\n}\nThread2(X* px)\n{\n ...\n px-&gt;SetState(kDone);\n ...\n}<\/i>\n<\/pre>\n<p>\nThere is a race condition here:\n<\/p>\n<ul>\n<li>Thread&nbsp;1 calls <code>X::Wait<\/code> and waits.\n<li>Thread&nbsp;2 calls <code>X::SetState<\/code>.\n<li>Thread&nbsp;2 gets pre-empted immediately after calling\n    <code>Set&shy;Event<\/code>.<\/p>\n<li>Thread&nbsp;1 wakes up from the\n    <code>Wait&shy;For&shy;Single&shy;Object<\/code>\n    call, notices that <code>mState == kDone<\/code>, and therefore\n    returns from the <code>X::Wait<\/code> method.<\/p>\n<li>Thread&nbsp;1 then destructs the <code>X<\/code> object, which\n    destroys the critical section.<\/p>\n<li>Thread&nbsp;2 finally runs and tries to leave a critical section\n    that has been destroyed.\n<\/ul>\n<p>\nThe fix was to enclose the <i>read<\/i> of <code>mState<\/code>\ninside a critical section:\n<\/p>\n<pre>\nX::Wait() {\n while(1) {\n   EnterCriticalSection(&amp;mCrit);\n   int state = mState;\n   LeaveCriticalSection(&amp;mCrit);\n   if(state == kDone)\n     break;\n   WaitForSingleObject(mEvent, INFINITE);\n }\n}\n<\/pre>\n<p>\nForgetting to enclose the read inside a critical section is a common\noversight.\nI&#8217;ve made it myself more than once.\nYou say to yourself,\n&#8220;I don&#8217;t need a critical section here.\nI&#8217;m just reading a value which can safely be read atomically.&#8221;\nBut you forget that the critical section isn&#8217;t just for protecting\nthe write to the variable;\nit&#8217;s also to protect all the other actions that take place under\nthe critical section.\n<\/p>\n<p>\nAnd just to make it so I actually did some work today,\nI leave you with this puzzle based on an actual customer problem:\n<\/p>\n<pre>\n<i>class BufferPool {\npublic:\n BufferPool() { ... }\n ~BufferPool() { ... }\n Buffer *GetBuffer()\n {\n  Buffer *pBuffer = FindFreeBuffer();\n  if (pBuffer) {\n   pBuffer-&gt;mIsFree = false;\n  }\n  return pBuffer;\n }\n void ReturnBuffer(Buffer *pBuffer)\n {\n  pBuffer-&gt;mIsFree = true;\n }\nprivate:\n Buffer *FindFreeBuffer()\n {\n  EnterCriticalSection(&amp;mCrit);\n  Buffer *pBuffer = NULL;\n  for (int i = 0; i &lt; 8; i++) {\n   if (mBuffers[i].mIsFree) {\n    pBuffer = &amp;mBuffers[i];\n    break;\n   }\n  }\n  LeaveCriticalSection(&amp;mCrit);\n  return pBuffer;\n }\nprivate:\n CRITICAL_SECTION mCrit;\n Buffer mBuffers[8];\n};<\/i>\n<\/pre>\n<p>\nThe real class was significantly more complicated than this,\nbut I&#8217;ve distilled the problem to its essence.\n<\/p>\n<p>\nThe customer added,\n&#8220;I tried declaring <code>mIs&shy;Free<\/code> as a volatile variable,\nbut that didn&#8217;t seem to help.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is common to have a critical section which protects against concurrent writes to a variable or collection of variables. But if you protect a write with a critical section, you may also want to protect the read, because the read might race against the write. Adam Rosenfield shared his experience with this issue in [&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-9003","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It is common to have a critical section which protects against concurrent writes to a variable or collection of variables. But if you protect a write with a critical section, you may also want to protect the read, because the read might race against the write. Adam Rosenfield shared his experience with this issue in [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9003","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=9003"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9003\/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=9003"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=9003"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=9003"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}