{"id":94766,"date":"2016-11-23T07:00:00","date_gmt":"2016-11-23T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94766"},"modified":"2019-03-13T10:34:05","modified_gmt":"2019-03-13T17:34:05","slug":"20161123-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20161123-00\/?p=94766","title":{"rendered":"Lock free many-producer\/single-consumer patterns: A work queue of identical non-coalescable events"},"content":{"rendered":"<p>Onward with our miniseries on lock-free many-producer\/single-consumer patterns. Today, we&#8217;re going to look at the case where you have a work queue where there can be multiple work items, and you need to perform them all, but each item is identical. <\/p>\n<p>For example, you may have a <i>Buy It<\/i> button. Each time the user clicks the button, you want to run a transaction. But each button press is equivalent; all that&#8217;s important is the number of times the user pushed the button. <\/p>\n<p>Okay, that&#8217;s not a very good example, but it&#8217;ll have to do. <\/p>\n<p>One way of doing this is with a semaphore, where the number of tokens in the semaphore is the number of work items left to be done. But let&#8217;s stick with our current pattern where the producers need to manually wake the consumer, say with a message, and we want to minimize the number of times we need to perform the wake ritual. <\/p>\n<pre>\nLONG WorkCount;\n\nvoid RequestWork()\n{\n if (InterlockedIncrement(&amp;WorkCount) == 1) {\n  \/\/ You provide the WakeConsumer() function.\n  WakeConsumer();\n }\n}\n\n\/\/ You call this function when the consumer receives the\n\/\/ signal raised by WakeConsumer().\nvoid ConsumeWork()\n{\n while (InterlockedDecrementToZero(&amp;WorkCount)) {\n  DoSomeWork();\n }\n}\n\nbool InterlockedDecrementToZero(LONG volatile* value)\n{\n LONG original, result;\n do {\n  original = *value;\n  if (original == 0) return false;\n  result = original - 1;\n } while (InterlockedCompareExchange(value, result,\n                               original) != original);\n return true;\n}\n<\/pre>\n<p>The <code>Interlocked&shy;Decrement&shy;To&shy;Zero<\/code> function follows <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20040915-00\/?p=37863\">the pattern for building complex interlocked operations<\/a>, in this case, decrementing a number, but not decrementing it below zero. We check if the value is zero; if so, then stop and return <code>false<\/code>. Otherwise, try to swap it with the value one less than the current value. If that fails, then it means that another thread changed the <code>WorkCount<\/code> while we were busy thinking, so we start over. If we successfully decremented, then return <code>true<\/code>. <\/p>\n<p>The <code>Work&shy;Count<\/code> variable remembers how much work there is for the consumer to do. When the first piece of work arrives, we wake the consumer, and the consumer keeps draining the work until it&#8217;s all done. <\/p>\n<p>Remember, there is only one consumer, so if <code>Wake&shy;Consumer<\/code> is called while <code>Consume&shy;Work<\/code> is still running, the wake will not start a new consumer immediately. It will wait for the existing <code>Consume&shy;Work<\/code> to complete before starting a new <code>Consume&shy;Work<\/code>. <\/p>\n<p>Although this specific pattern may not be all that interesting, it can be viewed as a building block on top of which other patterns are built. We&#8217;ll look at one such next time. <\/p>\n<p><b>Exercise<\/b>: Why couldn&#8217;t the <code>Interlocked&shy;Decrement&shy;To&shy;Zero<\/code> function have been written like this? <\/p>\n<pre>\n<i>\/\/ Code in italics is wrong.\nLONG InterlockedDecrementToZero(LONG volatile* value)\n{\n LONG original = *value;\n if (original == 0) return false;\n InterlockedDecrement(value);\n return true;\n}<\/i>\n<\/pre>\n<p><b>Bonus chatter<\/b>: We could have avoided having to write the <code>Interlocked&shy;Decrement&shy;To&shy;Zero<\/code> by writing this instead: void ConsumeWork() {  LONG count = InterlockedExchange(&amp;WorkCount);  for (LONG i = 0; i &lt; count; i++) {   DoSomeWork();  } } <\/p>\n<p>Discuss. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>They&#8217;re all the same, but each one counts.<\/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-94766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>They&#8217;re all the same, but each one counts.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94766","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=94766"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94766\/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=94766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}