{"id":7820,"date":"2018-01-04T13:34:13","date_gmt":"2018-01-04T11:34:13","guid":{"rendered":"http:\/\/code.openark.org\/blog\/?p=7820"},"modified":"2018-01-04T13:37:10","modified_gmt":"2018-01-04T11:37:10","slug":"implementing-non-re-entrant-functions-in-golang","status":"publish","type":"post","link":"https:\/\/code.openark.org\/blog\/golang\/implementing-non-re-entrant-functions-in-golang","title":{"rendered":"Implementing non re-entrant functions in Golang"},"content":{"rendered":"<p>A non re-entrant function is a function that could only be executing once at any point in time, regardless of how many times it is being invoked and by how many goroutines.<\/p>\n<p>This post illustrates <em>blocking<\/em> non re-entrant functions and <em>yielding<\/em> non re-entrant functions implementations in <code>golang<\/code>.<\/p>\n<h3>A use case<\/h3>\n<p>A service is polling for some conditions, monitoring some statuses once per second. We want each status to be checked independently of others without blocking. An implementation might look like:<\/p>\n<pre>func main() {\n    tick := time.Tick(time.Second)\n    go func() {\n        for range tick {\n            go CheckSomeStatus()\n            go CheckAnotherStatus()\n        }\n    }()\n}\n<\/pre>\n<p>We choose to run each status check in its own goroutine so that <code>CheckAnotherStatus()<\/code> doesn&#8217;t wait upon <code>CheckSomeStatus()<\/code> to complete.<\/p>\n<p>Each of these checks typically take a very short amount of time, and much less than a second. What happens, though, if <code>CheckAnotherStatus()<\/code> itself takes more than one second to run? Perhaps there&#8217;s an unexpected network or disk latency affecting the execution time of the check.<\/p>\n<p>Does it make sense for the function to be executed twice at the same time? If not, we want it to be non re-entrant.<!--more--><\/p>\n<h3>Blocking, non-reentrant functions<\/h3>\n<p>The simple way to prevent a function from operating multiple times concurrently is using a <code>sync.Mutex<\/code>.<\/p>\n<p>Assuming we only care about calling this function from the loop above, we can implement the lock from outside the function:<\/p>\n<pre>import (\n    \"sync\"\n    \"time\"\n)\n\nfunc main() {\n    tick := time.Tick(time.Second)\n    var mu sync.Mutex\n    go func() {\n        for range tick {\n            go CheckSomeStatus()\n            go func() {\n                mu.Lock()\n                defer mu.Unlock()\n                CheckAnotherStatus()\n            }()\n        }\n    }()\n}\n<\/pre>\n<p>The above ensures <code>CheckAnotherStatus()<\/code> is not executed by multiple iterations of our loop concurrently. Any subsequent iterations of the loop whilst a previous execution of <code>CheckAnotherStatus()<\/code> is still running, will be blocked by the mutex.<\/p>\n<p>The <em>blocking<\/em> solution has the following properties:<\/p>\n<ul>\n<li>It ensures as many `CheckAnotherStatus()` invocations as the number of loop iterations.<\/li>\n<li>Assuming one execution of `CheckAnotherStatus()` stalls, subsequent iterations make for a pileup of requests to invoke same function.<\/li>\n<\/ul>\n<h3>Yielding, non re-entrant functions<\/h3>\n<p>In our status check story, it may not make sense for some 10 subsequent calls to pile up. One the stalled <code>CheckAnotherStatus()<\/code> execution completes, all 10 calls suddenly execute, sequentially, and possibly all complete within the next second, making for 10 identical checks at that same second.<\/p>\n<p>Another solution would be to <em>yield<\/em>. A <em>yielding<\/em> solution will:<\/p>\n<ul>\n<li>Abort execution of `CheckAnotherStatus()` if it is already being executed.<\/li>\n<li>Will run <em>at most<\/em> one execution of `CheckAnotherStatus()` per second.<\/li>\n<li>May in effect run less `CheckAnotherStatus()` invocations than the number of loop iterations.<\/li>\n<\/ul>\n<p>The solution is achieved via:<\/p>\n<pre>import (\n    \"sync\/atomic\"\n    \"time\"\n)\n\nfunc main() {\n    tick := time.Tick(time.Second)\n    var reentranceFlag int64\n    go func() {\n        for range tick {\n            go CheckSomeStatus()\n            go func() {\n                if atomic.CompareAndSwapInt64(&amp;reentranceFlag, 0, 1) {\n                    defer atomic.StoreInt64(&amp;reentranceFlag, 0)\n                } else {\n                    return\n                }\n                CheckAnotherStatus()\n            }()\n        }\n    }()\n}\n<\/pre>\n<p><code>atomic.CompareAndSwapInt64(&amp;amp;reentranceFlag, 0, 1)<\/code> will return <code>true<\/code> only when <code>reentranceFlag == 0<\/code>, and will atomically set it to <code>1<\/code>. In such case, entry is allowed and the function can be executed. <code>reentranceFlag<\/code> is kept at <code>1<\/code> until <code>CheckAnotherStatus()<\/code> completes, at which time it is reset. When <code>CompareAndSwapInt64(...)<\/code> returns <code>false<\/code> that means <code>reentranceFlag != 0<\/code>, meaning the function is already being executing by another goroutine. The code yields and silently exits the function.<\/p>\n<p>We have chosen to implement the non re-entrant code outside the function in question; we could have implemented it within the function itself. Also, I have a thing for <code>int64<\/code>. An <code>int32<\/code> will of course suffice.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A non re-entrant function is a function that could only be executing once at any point in time, regardless of how many times it is being invoked and by how many goroutines. This post illustrates blocking non re-entrant functions and yielding non re-entrant functions implementations in golang. A use case A service is polling for [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[130],"tags":[124],"class_list":["post-7820","post","type-post","status-publish","format-standard","hentry","category-golang","tag-golang"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2bZZp-228","_links":{"self":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/7820","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/comments?post=7820"}],"version-history":[{"count":11,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/7820\/revisions"}],"predecessor-version":[{"id":7831,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/7820\/revisions\/7831"}],"wp:attachment":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/media?parent=7820"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/categories?post=7820"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/tags?post=7820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}