{"id":1759,"date":"2018-11-12T15:13:10","date_gmt":"2018-11-12T15:13:10","guid":{"rendered":"http:\/\/www.max-sperling.bplaced.net\/?p=1759"},"modified":"2025-08-06T13:43:23","modified_gmt":"2025-08-06T13:43:23","slug":"threading-mutex-vs-atomic-c","status":"publish","type":"post","link":"http:\/\/www.max-sperling.bplaced.net\/?p=1759","title":{"rendered":"Threading &#8211; Reduce locks (C++)"},"content":{"rendered":"<p>With multithreading, you have to be careful to not create race conditions. The default way to do this is the usage of mutexes at all critical sections. This is annoying, reduces performance and can lead to deadlocks. For some scenarios, it&#8217;s a possibility to instead use atomics or lock-free containers.<\/p>\n<hr>\n<h2>The default way<\/h2>\n<h3>Mutexes<\/h3>\n<p>&#8230; can be used to sync anything.<\/p>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\nstd::mutex mtx;\r\nint num = 0;\r\n\r\nvoid inc() {\r\n  std::lock_guard&lt;std::mutex&gt; lock(mtx);\r\n  num++;\r\n}\r\n\r\nint main() {\r\n  std::thread t1(inc), t2(inc);\r\n  return 0;\r\n}\r\n<\/pre>\n<hr>\n<h2>Alternatives<\/h2>\n<h3>Atomics<\/h3>\n<p>&#8230; are used to sync primitive types.<\/p>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\nstd::atomic&lt;int&gt; num = 0;\r\n\r\nvoid inc() {\r\n  num++;\r\n}\r\n\r\nint main() {\r\n  std::thread t1(inc), t2(inc);\r\n  return 0;\r\n}\r\n<\/pre>\n<p>Depending on the use case, atomics are not necessarily more performant than locks.<\/p>\n<h3>Lock-free containers<\/h3>\n<p>&#8230; don&#8217;t need to sync at all.<\/p>\n<p>A very famous example is <a href=\"https:\/\/github.com\/uxlfoundation\/oneTBB\/tree\/v2022.2.0\/include\/oneapi\/tbb\">oneTBB<\/a> from Intel:<\/p>\n<ul>\n<li>tbb::concurrent_queue<\/li>\n<li>tbb::concurrent_unordered_map<\/li>\n<li>tbb::concurrent_vector<\/li>\n<\/ul>\n<p>You can just use supported containers, and not all operations necessarily are thread-safe.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With multithreading, you have to be careful to not create race conditions. The default way to do this is the<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false},"categories":[63],"tags":[],"_links":{"self":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/1759"}],"collection":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1759"}],"version-history":[{"count":8,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/1759\/revisions"}],"predecessor-version":[{"id":18976,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/1759\/revisions\/18976"}],"wp:attachment":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1759"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1759"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1759"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}