{"id":106883,"date":"2022-07-22T07:00:00","date_gmt":"2022-07-22T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106883"},"modified":"2022-11-30T06:45:13","modified_gmt":"2022-11-30T14:45:13","slug":"20220722-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220722-00\/?p=106883","title":{"rendered":"Using C++\/WinRT&#8217;s <CODE>final_release<\/CODE> to control which thread destructs your object"},"content":{"rendered":"<p>It is often that case that an object is intended to be used only from a single thread, particularly if it is tied to the user interface somehow, since user interface objects are generally single-threaded. On the other hand, it may have to subscribe to events that are raised from background threads.<\/p>\n<pre>namespace winrt\r\n{\r\n    using namespace Windows::System::Power;\r\n}\r\n\r\nstruct MyViewModel : MyViewModelT&lt;MyViewModel&gt;\r\n{\r\n    ...\r\n\r\n    winrt::fire_and_forget OnEnergySaverStatusChanged(\r\n        winrt::IInspectable const&amp;, winrt::IInspectable const&amp;)\r\n    {\r\n        auto lifetime = get_strong();\r\n        co_await winrt::resume_foreground(Dispatcher());\r\n        m_isEnergySaverOn = (winrt::PowerManager::EnergySaverStatus()\r\n                              == winrt::EnergySaverStatus::On);\r\n        RaiseProperyChangeEvent(L\"IsEnergySaverOn\");\r\n    }\r\n\r\n    winrt::EnergySaverStatusChanged_revoker m_energySaverStatusChangedToken =\r\n        winrt::PowerManager::EnergySaverStatusChanged(\r\n            { get_weak(), &amp;MyViewModel::OnEnergySaverStatusChanged });\r\n};\r\n<\/pre>\n<p>In the above example, we have a view model that tracks the system Energy Saver status. The change notification for this is raised on a background thread, so we need to switch to the foreground thread before doing our calculations and raising the property-change event.<\/p>\n<p>This pattern is common for many types of notifications: Receive the notification on a background thread and immediately switch to the UI thread to process it. Doing all the work on the UI thread avoids race conditions.<\/p>\n<p>But there&#8217;s a small problem here: There&#8217;s a race condition if the foreground thread completes its work before the background thread releases its temporary strong reference.<\/p>\n<p>To make the weak and strong references more explicit, let me rewrite the code this way:<\/p>\n<pre>struct MyViewModel : MyViewModelT&lt;MyViewModel&gt;\r\n{\r\n    ...\r\n\r\n    winrt::EnergySaverStatusChanged_revoker m_energySaverStatusChangedToken =\r\n        winrt::PowerManager::EnergySaverStatusChanged(\r\n            [weak = get_weak()](auto&amp;&amp;, auto&amp;&amp;)\r\n            -&gt; winrt::fire_and_forget {\r\n                if (auto strong = weak.get()) {\r\n                    strong-&gt;Dispatcher().RunAsync([strong] {\r\n                        m_isEnergySaverOn = (winrt::PowerManager::EnergySaverStatus()\r\n                                              == winrt::EnergySaverStatus::On);\r\n                        RaiseProperyChangeEvent(L\"IsEnergySaverOn\");\r\n                    });\r\n                }\r\n            });\r\n};\r\n<\/pre>\n<p>Now we can follow the reference counts. Initially the view model&#8217;s reference count is 1 because the view has a reference to it.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px gray;\">UI thread<\/td>\n<td style=\"border: solid 1px gray;\">Background thread<\/td>\n<td style=\"border: solid 1px gray;\">Reference count<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">EnergySaverStatusChanged<\/td>\n<td style=\"border: 1px gray; border-style: none solid; text-align: center;\">1<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">get strong reference<\/td>\n<td style=\"border: 1px gray; border-style: none solid; text-align: center;\">2<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">capture strong reference into lambda<\/td>\n<td style=\"border: 1px gray; border-style: none solid; text-align: center;\">3<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">View tears down<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">View model released<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid; text-align: center;\">2<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">RunAsync<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">update <code>m_isEnergySaverOn<\/code><\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">raise property change event<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid;\">destruct strong reference inside lambda<\/td>\n<td style=\"border: 1px gray; border-style: none solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid; text-align: center;\">1<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none solid solid;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: none solid solid;\">destruct strong reference<\/td>\n<td style=\"border: 1px gray; border-style: none solid solid; text-align: center;\">0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In this unfortunate sequence of events, the last reference is released on the background thread, and the view model therefore runs its destructor on the background thread, which is bad news because the view model really is a single-threaded object, and its destructor is going to assume that it is running on the UI thread. The reference on the background thread exists for the sole purpose of getting control back to the UI thread, but it ends up being the one holding the bag when everything cleans up.<\/p>\n<p>The fix here is to use <code>final_<wbr \/>release<\/code> to get control back to the UI thread for the purpose of destructing there.<\/p>\n<pre>struct MyViewModel : MyViewModelT&lt;MyViewModel&gt;\r\n{\r\n    ...\r\n\r\n    winrt::fire_and_forget final_release(std::unique_ptr&lt;MyViewModel&gt; self)\r\n    {\r\n        co_await winrt::resume_foreground(self-&gt;Dispatcher());\r\n        \/\/ destruct the object on the UI thread\r\n    }\r\n\r\n    ...\r\n};\r\n<\/pre>\n<p>If your implementation class has a method called <code>final_release<\/code>, it will be called with a <code>std::unique_ptr<\/code> holding the object that is about to be destructed. This gives you a chance to do something just before destruction, and a common reason for doing this is to move the <code>unique_ptr<\/code> to the UI thread, so that when it destructs, the underlying object destructs on the UI thread.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once it&#8217;s yours, you can take it wherever you like.<\/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-106883","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Once it&#8217;s yours, you can take it wherever you like.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106883","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=106883"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106883\/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=106883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}