{"id":22655,"date":"2019-01-28T06:08:25","date_gmt":"2019-01-28T14:08:25","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/?p=22655"},"modified":"2019-02-18T17:47:25","modified_gmt":"2019-02-18T17:47:25","slug":"concurrency-code-analysis-in-visual-studio-2019","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/concurrency-code-analysis-in-visual-studio-2019\/","title":{"rendered":"Concurrency Code Analysis in Visual Studio 2019"},"content":{"rendered":"<h2>Concurrency Code Analysis in Visual Studio 2019<\/h2>\n<p>The battle against concurrency bugs poses a serious challenge to C++ developers. The problem is exacerbated by the advent of multi-core and many-core architectures. To cope with the increasing complexity of multithreaded software, it is essential to employ better tools and processes to help developers adhere to proper locking discipline. In this blog post, we\u2019ll walk through a completely rejuvenated Concurrency Code Analysis toolset we are shipping with Visual Studio 2019 Preview 2.<\/p>\n<h3>A perilous landscape<\/h3>\n<p>The most popular concurrent programming paradigm in use today is based on threads and locks. Many developers in the industry have invested heavily in multithreaded software. Unfortunately, developing and maintaining multithreaded software is difficult due to a lack of mature multi-threaded software development kits.<\/p>\n<p>Developers routinely face a dilemma in how to use synchronization. Too much may result in deadlocks and sluggish performance. Too little may lead to race conditions and data inconsistency. Worse yet, the Win32 threading model introduces additional pitfalls. Unlike in managed code, lock acquire and lock release operations are not required to be syntactically scoped in C\/C++. Applications therefore are vulnerable to mismatched locking errors. Some Win32 APIs have subtle synchronization side effects. For example, the popular \u201cSendMessage\u201d call may induce hangs among UI threads if not used carefully. Because concurrency errors are intermittent, they are among the hardest to catch during testing. When encountered, they are difficult to reproduce and diagnose. Therefore, it is highly beneficial to apply effective multi-threading programming guidelines and tools as early as possible in the engineering process.<\/p>\n<h3>Importance of locking disciplines<\/h3>\n<p>Because one generally cannot control all corner cases induced by thread interleaving, it is essential to adhere to certain locking disciplines when writing multithreaded programs. For example, following a lock order while acquiring multiple locks or using std::lock() consistently helps to avoid deadlocks; acquiring the proper guarding lock before accessing a shared resource helps to prevent race conditions. However, these seemingly simple locking rules are surprisingly hard to follow in practice.<\/p>\n<p>A fundamental limitation in today\u2019s programming languages is that they do not directly support specifications for concurrency requirements. Programmers can only rely on informal documentation to express their intention regarding lock usage. Thus, developers have a clear need for pragmatic tools that help them confidently apply locking rules.<\/p>\n<h2>Concurrency Toolset<\/h2>\n<p>To address the deficiency of C\/C++ in concurrency support, we had shipped an initial version of concurrency analyzer back in Visual Studio 2012, with promising initial results. This tool had a basic understanding of the most common Win32 locking APIs and concurrency related annotations.<\/p>\n<p>In Visual Studio 2019 Preview 2, we are excited to announce a completely rejuvenated set of concurrency checks to meet the needs of modern C++ programmers. The toolset comprises a local intra-procedural lock analyzer with built-in understanding of common Win32 locking primitives and APIs, RAII locking patterns, and STL locks.<\/p>\n<h3>Getting started<\/h3>\n<p>The concurrency checks are integrated as part of the code analysis toolset in Visual Studio. The default \u201cMicrosoft Native Recommended Ruleset\u201d for the project comprises the following rules from the concurrency analyzer. This means, whenever you run code analysis in your project, these checks are automatically executed. These checks are also automatically executed as part of the background code analysis runs for your project. For each rule, you can click on the link to learn more about the rule and its enforcement with clear examples.<\/p>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26100\">C26100<\/a>: Race condition. Variable should be protected by a lock.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26101\">C26101<\/a>: Failing to use interlocked operation properly for a variable.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26110\">C26110<\/a>: Caller failing to acquire a lock before calling a function which expects the lock to be acquired prior to being called.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26111\">C26111<\/a>: Caller failing to release a lock before calling a function which expects the lock to be released prior to being called.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26112\">C26112<\/a>: Caller cannot hold any lock before calling a function which expects no locks be held prior to being called.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26115\">C26115<\/a>: Failing to release a lock in a function. This introduces an orphaned lock.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26116\">C26116<\/a>: Failing to acquire a lock in a function, which is expected to acquire the lock.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26117\">C26117<\/a>: Releasing an unheld lock in a function.<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/c26140\">C26140<\/a>: Undefined lock kind specified on the lock.<\/li>\n<\/ul>\n<p>If you want to try out the full set of rules from this checker, there\u2019s a ruleset just for that. You must right click on Project &gt; Properties &gt; Code Analysis &gt; General &gt; Rulesets &gt; Select \u201cConcurrency Check Rules\u201d.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ConcurrencyCheckRuleset1.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22675\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/ConcurrencyCheckRuleset1.png\" alt=\"Screenshot of the Code Analysis properties page that shows the ConcurrencyCheck Rules ruleset selected.\" width=\"1159\" height=\"831\" \/><\/a><\/p>\n<p>You can learn more about each rule enforced by the checker by searching for rule numbers in the ranges C26100 \u2013 C26199 in our <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/code-analysis-for-c-cpp-warnings\">Code Analysis for C\/C++ warning<\/a> document.<\/p>\n<h3>Concurrency toolset in action<\/h3>\n<p>The initial version of concurrency toolset was capable of finding concurrency related issues like race conditions, locking side effects, and potential deadlocks in mostly C-like code.<\/p>\n<p>The tool had in-built understanding of standard Win32 locking APIs. For custom functions with locking side effects, the tool understood a number of concurrency related annotations. These annotations allowed the programmer to express locking behavior. Here are some examples of concurrency related annotations.<\/p>\n<ul>\n<li>_Acquires_lock_(lock): Function acquires the lock object \u201clock\u201d.<\/li>\n<li>_Releases_lock_(lock): Function releases the lock object \u201clock\u201d.<\/li>\n<li>_Requires_lock_held_(lock): Lock object \u201clock\u201d must be acquired before entering this function.<\/li>\n<li>_Guarded_by_(lock) data: \u201cdata\u201d must always be protected by lock object \u201clock\u201d.<\/li>\n<li>_Post_same_lock(lock1, lock2): \u201clock1\u201d and \u201clock2\u201d are aliases.<\/li>\n<\/ul>\n<p>For a complete set of concurrency related annotations, please see this article <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/annotating-locking-behavior\">Annotating Locking Behavior<\/a>.<\/p>\n<p>The rejuvenated version of the toolset builds on the strengths of the initial version by extending its analysis capabilities to modern C++ code. For example, it now understands STL locks and RAII patterns without having to add any annotations.<\/p>\n<p>Now that we have talked about how the checker works and how you can enable them in your project, let\u2019s look at some real-world examples.<\/p>\n<h4>Example 1<\/h4>\n<p>Can you spot an issue with this code<sup>1<\/sup> ?<\/p>\n<pre class=\"lang:cpp decode=true\">struct RequestProcessor {\u200b\r\n\u202f\u202f\u202f CRITICAL_SECTION cs_;\u200b\r\n\u202f\u202f\u202f std::map&lt;int, Request*&gt; cache_;\u200b\r\n\u200b\r\n\u202f\u202f\u202f bool HandleRequest(int Id, Request* request) {\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f EnterCriticalSection(&amp;cs_);\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f if (cache_.find(Id) != cache_.end())\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f return false;\u202f\u202f\u202f\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f cache_[Id] = request;\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f LeaveCriticalSection(&amp;cs_);\u202f\u202f\u202f\u200b\r\n\u202f\u202f\u202f }\u200b\r\n\u202f\u202f\u202f void DumpRequestStatistics() {\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f for (auto&amp; r : cache_)\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f std::cout &lt;&lt; \"name: \" &lt;&lt; r.second-&gt;name &lt;&lt; std::endl;\u200b\r\n\u202f\u202f\u202f }\u200b\r\n};\u200b\r\n<\/pre>\n<p><sup>1<\/sup> If you have seen <a href=\"https:\/\/www.youtube.com\/watch?v=p5iwbuAFpUo\">this<\/a> talk given by Anna Gringauze in CppCon 2018, this code may seem familiar to you.<\/p>\n<p>Let\u2019s summarize what\u2019s going on here:<\/p>\n<ol>\n<li>In function <code>HandleRequest<\/code>, we acquire lock <code>cs<\/code> on line 6. However, we return early from line 8 without ever releasing the lock.<\/li>\n<li>In function <code>HandleRequest<\/code>, we see that <code>cache_<\/code> access must be protected by lock <code>cs<\/code>. However, in a different function, <code>DumpStatistics<\/code>, we access <code>cache_<\/code> without acquiring any lock.<\/li>\n<\/ol>\n<p>If you run code analysis on this example, you\u2019ll get a warning in method <code>HandleRequest<\/code>, where it will complain about the leaked critical section (issue #1):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/FailingToRelease21.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22715\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/FailingToRelease21.png\" alt=\"This shows the leaked critical section warning from the concurrency analyzer.\" width=\"1383\" height=\"674\" \/><\/a><\/p>\n<p>Next, if you add the <code>_Guarded_by_<\/code> annotation on the field <code>cache_<\/code> and select ruleset \u201cConcurrency Check Rules\u201d, you\u2019ll get an additional warning in method <code>DumpRequestStatistics<\/code> for the possible race condition (issue #2):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/RaceCondition11.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22725\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/RaceCondition11.png\" alt=\"This shows the potential race condition warning from the concurrency analyzer.\" width=\"2496\" height=\"802\" \/><\/a><\/p>\n<h4>Example 2<\/h4>\n<p>Let\u2019s look at a more modern example. Can you spot an issue with this code<sup>1<\/sup> ?<\/p>\n<pre class=\"lang:cpp decode=true\">struct RequestProcessor2 {\u200b\r\n\u202f\u202f\u202f std::mutex\u200b m_;\r\n\u202f\u202f\u202f std::map&lt;int, Request*&gt; cache_;\u200b\r\n\u200b\r\n\u202f\u202f\u202f void HandleRequest(int Id, Request* request) {\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f std::lock_guard grab(m_);\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f if (cache_.find(Id) != cache_.end())\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f return;\u202f\u202f\u202f\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f cache_[Id] = request;\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u200b\r\n\u202f\u202f\u202f }\u200b\r\n\u202f\u202f\u202f void DumpRequestStatistics() {\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f for (auto&amp; r : cache_)\u202f\u200b\r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f\u202f std::cout &lt;&lt; \"name: \" &lt;&lt; r.second-&gt;name &lt;&lt; std::endl;\u200b\r\n\u202f\u202f\u202f }\u200b\r\n};\r\n<\/pre>\n<p>As expected, we don\u2019t get any warning in <code>HandleRequest<\/code> in the above implementation using <code>std::lock_guard<\/code>. However, we still get a warning in <code>DumpRequestStatistics<\/code> function:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/RaceCondition21.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-22735\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2019\/01\/RaceCondition21.png\" alt=\"This shows the potential race condition warning from the concurrency analyzer.\" width=\"2518\" height=\"685\" \/><\/a><\/p>\n<p>There are a couple of interesting things going on behind the scenes here. First, the checker understands the locking nature of <code>std::mutex<\/code>. Second, it understands that <code>std::lock_guard<\/code> holds the mutex and releases it during destruction when its scope ends.<\/p>\n<p>This example demonstrates some of the capabilities of the rejuvenated concurrency checker and its understanding of STL locks and RAII patterns.<\/p>\n<h2>Give us feedback<\/h2>\n<p>We\u2019d love to hear from you about your experience of using the new concurrency checks. Remember to switch to \u201cConcurrency Check Rules\u201d for your project to explore the full capabilities of the toolset. If there are specific concurrency patterns you\u2019d like us to detect at compile time, please let us know.<\/p>\n<p>If you have suggestions or problems with this check \u2014 or any Visual Studio feature \u2014 either <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/ide\/how-to-report-a-problem-with-visual-studio-2017\">Report a Problem<\/a> or post on <a href=\"https:\/\/developercommunity.visualstudio.com\/spaces\/62\/index.html\">Developer Community<\/a>. We&#8217;re also on Twitter at <a href=\"https:\/\/twitter.com\/visualc\">@VisualC<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Concurrency Code Analysis in Visual Studio 2019 The battle against concurrency bugs poses a serious challenge to C++ developers. The problem is exacerbated by the advent of multi-core and many-core architectures. To cope with the increasing complexity of multithreaded software, it is essential to employ better tools and processes to help developers adhere to proper [&hellip;]<\/p>\n","protected":false},"author":324,"featured_media":22812,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[270,230],"tags":[119],"class_list":["post-22655","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcement","category-new-feature","tag-code-analysis"],"acf":[],"blog_post_summary":"<p>Concurrency Code Analysis in Visual Studio 2019 The battle against concurrency bugs poses a serious challenge to C++ developers. The problem is exacerbated by the advent of multi-core and many-core architectures. To cope with the increasing complexity of multithreaded software, it is essential to employ better tools and processes to help developers adhere to proper [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/22655","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/324"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=22655"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/22655\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/22812"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=22655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=22655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=22655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}