{"id":104466,"date":"2020-11-20T07:00:00","date_gmt":"2020-11-20T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104466"},"modified":"2020-11-20T06:21:26","modified_gmt":"2020-11-20T14:21:26","slug":"20201120-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201120-00\/?p=104466","title":{"rendered":"How thread-safe is the Windows Runtime PropertySet object?"},"content":{"rendered":"<p>A customer was looking for a thread-safe collection type, and they found the Windows Runtime <code>PropertySet<\/code> object. Is this thing thread-safe?<\/p>\n<p>Yes, the <code>PropertySet<\/code> object is thread-safe.<\/p>\n<p>However, it still may not be what you want.<\/p>\n<p>The <code>PropertySet<\/code> object is thread-safe in the sense that all of its operations are atomic. Concurrent usage from multiple threads will be consistent with some sequential order.<\/p>\n<p>For example, if two threads both attempt to insert different values into the property set under the same key, it will be &#8220;last writer wins&#8221; with some choice of &#8220;last&#8221;. If one thread attempts to insert a value under a key at the same time another thread attempts to retrieve the value under that key, the reader will either get the old value or the new value, not some weird in-between value.<\/p>\n<p>That said, the available operations on a <code>Property\u00adSet<\/code> may not be sufficient for your desired concurrent usage.<\/p>\n<p>Here&#8217;s what you can do with a <code>Property\u00adSet<\/code>, or more generally, any <code>IMap&lt;K, V&gt;<\/code>:\u00b9<\/p>\n<ul>\n<li>Obtain the number of items by requesting the <code>Size<\/code> property.<\/li>\n<li>Empty the collection by calling <code>Clear()<\/code>.<\/li>\n<li>Check if a key is present by calling <code>HasKey()<\/code>.<\/li>\n<li>Look up the value associated with a key by calling <code>Lookup()<\/code>.<\/li>\n<li>Add or update an item by calling <code>Insert<\/code>. The return value tells you whether an existing item was replaced, or a new item was created.<\/li>\n<li>Remove an item by calling <code>Remove<\/code>.<\/li>\n<\/ul>\n<p>That&#8217;s it. In particular, you don&#8217;t have methods like <code>GetOrCreate<\/code> which atomically retrieves an existing value or manufactures one if it doesn&#8217;t exist yet. Or <code>InsertIfNew<\/code> which atomically creates a new value but doesn&#8217;t modify any existing one. If you need operations like those, then you&#8217;ll have to create them yourselves, and that means adding your own lock around the <code>Property\u00adSet<\/code>.<\/p>\n<p>At which point, maybe you realize the thread-safety of a <code>Property\u00adSet<\/code> doesn&#8217;t buy you much, seeing as you&#8217;re going to need a lock anyway. You may as well use a <code>std::map<\/code> or some other more convenient associative container.<\/p>\n<p>\u00b9 These are the methods available at the ABI level. Language projections may synthesize other methods out of these methods, but if those other methods involve multiple calls, then atomicity is lost.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s thread-safe as far as it goes, but you may want to go further.<\/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-104466","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s thread-safe as far as it goes, but you may want to go further.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104466","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=104466"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104466\/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=104466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}