{"id":104973,"date":"2021-03-17T07:00:00","date_gmt":"2021-03-17T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104973"},"modified":"2021-03-16T20:06:55","modified_gmt":"2021-03-17T03:06:55","slug":"20210317-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210317-00\/?p=104973","title":{"rendered":"Creating other types of synchronization objects that can be used with co_await, part 7: The mutex and recursive"},"content":{"rendered":"<p>Our next stop in <a title=\"Creating other types of synchronization objects that can be used with co_await, part 3: Parallel resumption\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210311-00\/?p=104949\"> showing off our library for building awaitable synchronization objects<\/a> are the mutex and recursive mutex.<\/p>\n<p>The mutex and recursive mutex are strange objects when applied to coroutines, because the traditional mutex and recursive mutex apply to threads, and threads are this implied context that every function has and shares with the functions it calls, even though it may not realize it. But coroutines don&#8217;t have that. When one coroutine awaits another coroutine, there is no formal connection between the two, so when you do this:<\/p>\n<pre>IAsyncAction Outer()\r\n{\r\n    co_await some_mutex.lock();\r\n    co_await Inner();\r\n}\r\n\r\nIAsyncAction Inner()\r\n{\r\n    some_mutex.unlock();\r\n}\r\n<\/pre>\n<p>the mutex has no way of knowing that the <code>Outer<\/code> lock matches the <code>Inner<\/code> unlock. It just has to trust the caller.<\/p>\n<p>The lack of coroutine flow identity is particularly troublesome for the recursive mutex, because it has no way of knowing whether a second lock came from the same logical coroutine chain that performed the initial lock.<\/p>\n<pre>IAsyncAction Outer()\r\n{\r\n    co_await some_mutex.lock();\r\n    co_await Inner();\r\n    some_mutex.unlock();\r\n}\r\n\r\nIAsyncAction Inner()\r\n{\r\n    co_await some_mutex.lock();\r\n    something();\r\n    some_mutex.unlock();\r\n}\r\n<\/pre>\n<p>If <code>some_<wbr \/>mutex<\/code> were an asynchronous recursive mutex, it wouldn&#8217;t be able to determine whether the call from <code>Inner<\/code> should be allowed, since it has no access to coroutine identity, nor to the dependency relationships among coroutines.<\/p>\n<p>Basically, there are no coroutine mutexes or recursive mutexes. Recursive mutexes simply cannot exist, and once you strip away the thread identity features of mutexes, all you have left is an auto-reset event.<\/p>\n<pre>using awaitable_mutex = awaitable_auto_reset_event;\r\n<\/pre>\n<p>But the shared mutex, that&#8217;s interesting. We&#8217;ll look at that next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The mutex and recursive mutex as strange beasts in the world of coroutines.<\/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-104973","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The mutex and recursive mutex as strange beasts in the world of coroutines.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104973","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=104973"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104973\/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=104973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}