{"id":6562,"date":"2023-05-15T08:12:32","date_gmt":"2023-05-15T08:12:32","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/dealing-with-mutation-locking\/"},"modified":"2023-08-23T17:04:50","modified_gmt":"2023-08-23T17:04:50","slug":"dealing-with-mutation-locking","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/dealing-with-mutation-locking\/","title":{"rendered":"Dealing with Mutation: Locking"},"content":{"rendered":"<p>Locking is a classical way to protect a shared, mutable state. Today, I will present the two variants, Scoped Locking and Strategized Locking.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6560\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/DealingWithMutation.png\" alt=\"DealingWithMutation\" width=\"650\" height=\"330\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/DealingWithMutation.png 1234w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/DealingWithMutation-300x152.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/DealingWithMutation-1024x519.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/DealingWithMutation-768x390.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>Locking is a straightforward idea to protect a critical section. A critical section is a section of code that, at most, one thread can use at any time.<\/p>\n<h2>Scoped Locking<\/h2>\n<p>Scoped locking is the idea of <a href=\"https:\/\/www.modernescpp.com\/index.php\/the-proxy-pattern\"><code>RAII<\/code> <\/a>applied to a <a href=\"https:\/\/www.modernescpp.com\/index.php\/threads-sharing-data\">mutex<\/a>. Scoped locking is also known as synchronized block and guard. The key idea of this idiom is to bind the resource acquisition and release to an object\u2019s lifetime. As the name suggests, the lifetime of the object is scoped. Scoped means that the C++ run time is responsible for object destruction and, therefore, for releasing the resource.<\/p>\n<p>The class <code>ScopedLock<\/code> implements Scoped Locking.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ scopedLock.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;mutex&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;new&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">ScopedLock<\/span>{\r\n  <span style=\"color: #9999ff;\">private:<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&amp;<\/span> mut;\r\n  <span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">explicit<\/span> <span style=\"color: #cc00ff;\">ScopedLock<\/span>(std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&amp;<\/span> m)<span style=\"color: #555555;\">:<\/span> mut(m){                      <em><span style=\"color: #0099ff;\">\/\/ (1)<\/span><\/em>\r\n\t\tmut.lock();                                          <em><span style=\"color: #0099ff;\">\/\/ (2)<\/span><\/em>\r\n\t\tstd<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span>  <span style=\"color: #cc3300;\">\"Lock the mutex: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #555555;\">&amp;<\/span>mut <span style=\"color: #555555;\">&lt;&lt;<\/span>   <span style=\"color: #cc3300;\">'\\n'<\/span>; \r\n    }\r\n    <span style=\"color: #555555;\">~<\/span>ScopedLock(){\r\n\t\tstd<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Release the mutex: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #555555;\">&amp;<\/span>mut <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>; \r\n\t\tmut.unlock();                                        <em><span style=\"color: #0099ff;\">\/\/ (3)<\/span><\/em>\r\n    }\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n\r\n  std<span style=\"color: #555555;\">::<\/span>mutex mutex1;\r\n  ScopedLock scopedLock1{mutex1};\r\n\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">Before local scope\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n  {\r\n    std<span style=\"color: #555555;\">::<\/span>mutex mutex2;\r\n    ScopedLock scopedLock2{mutex2};\r\n  }                                                                <em><span style=\"color: #0099ff;\">\/\/ (4)<\/span><\/em>\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"After local scope\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n  \r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">Before try-catch block\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n  try{\r\n      std<span style=\"color: #555555;\">::<\/span>mutex mutex3;\r\n      ScopedLock scopedLock3{mutex3};\r\n      <span style=\"color: #006699; font-weight: bold;\">throw<\/span> std<span style=\"color: #555555;\">::<\/span>bad_alloc();\r\n  }                                                                <em><span style=\"color: #0099ff;\">\/\/ (5)<\/span><\/em>\r\n  <span style=\"color: #006699; font-weight: bold;\">catch<\/span> (std<span style=\"color: #555555;\">::<\/span>bad_alloc<span style=\"color: #555555;\">&amp;<\/span> e){\r\n      std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> e.what();\r\n  }\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">After try-catch block\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n  \r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n  \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><code>ScopedLock<\/code> gets its mutex by reference (line 1). The mutex is locked in the constructor (line 2) and unlocked in the destructor (line 3). Thanks to the RAII idiom, the object\u2019s destruction and, therefore, the unlocking of the mutex is done automatically.<\/p>\n<p>The scope of <code>scopedLock1<\/code> ends at the end of the main function. Consequentially, <code>mutex1<\/code> is unlocked. The same holds for <code>mutex2<\/code>&nbsp; and <code>mutex3<\/code>. They are automatically unlocked at the end of their local scopes (lines 4 and 5). For <code>mutex3<\/code>, the destructor of the <code>scopedLock3<\/code> is also invoked if an exception occurs. Interestingly, <code>mutex3<\/code> reuses the memory of <code>mutex2<\/code> because both have the same address.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6561\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/scopedLock.png\" alt=\"scopedLock\" width=\"440\" height=\"424\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/scopedLock.png 440w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/scopedLock-300x289.png 300w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/p>\n<p>Scoped locking has the following advantages and disadvantages.<\/p>\n<ul>\n<li><strong>Advantages:<\/strong>\n<ul>\n<li>Robustness, because the locks are automatically acquired and released<\/li>\n<\/ul>\n<\/li>\n<li><strong>Disadvantages:<\/strong>\n<ul>\n<li>Recursive locking of a <code>std::mutex<\/code> is undefined behavior and may typically cause a deadlock<\/li>\n<li>Locks are not automatically released if the c function <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/program\/longjmp\"><code>longjmp<\/code> <\/a>is used; <code>longjpm<\/code> does not call C++ destructors of scoped objects<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>C++17 supports locks in four variations. C++ has a <code>std::lock_guard \/ std::scoped_lock<\/code> for the simple and a <code>std::unique_lock \/ std::shared_lock<\/code> for the advanced use cases such as explicit locking or unlocking of the mutex. You can read more about mutex and locks in my previous post, &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/prefer-locks-to-mutexes\">Prefer Locks to Mutexes<\/a>&#8220;.<\/p>\n<p>Strategized Locking often applies Scoped Locking.<\/p>\n<\/p>\n<h2>Strategized Locking<\/h2>\n<p>Assume you write code such as a library, which should be used in various domains, including concurrent ones. To be safe, you protect the critical sections with a lock. If your library now runs in a single-threaded environment, you have a performance issue because you implemented an expensive synchronization mechanism that is unnecessary. Now, Strategized Locking comes to your rescue. Strategized locking is the idea of the<a href=\"https:\/\/en.wikipedia.org\/wiki\/Strategy_pattern\"> Strategy Pattern<\/a> applied to locking. This means putting your locking strategy into an object and making it into a pluggable component of your system.<\/p>\n<p>Two typical ways to implement Strategized Locking are run-time polymorphism (object orientation) or compile-time polymorphism (templates). Both ways improve the customization and extension of the locking strategy, ease the maintenance of the system, and support the reuse of components. Implementing the strategized locking at run-time or compile-time polymorphism differs in various aspects.<\/p>\n<ul>\n<li><strong>Advantages:<\/strong>\n<ul>\n<li>Run-time Polymorphism\n<ul>\n<li>allows it to configure the locking strategy during run time.<\/li>\n<li>is easier to understand for developers who have an object-oriented background.<\/li>\n<\/ul>\n<\/li>\n<li>Compile-Time Polymorphism\n<ul>\n<li>has no abstraction penalty.<\/li>\n<li>has a flat hierarchy.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li><strong>Disadvantages:<\/strong>\n<ul>\n<li>Run-time Polymorphism\n<ul>\n<li>needs an additional pointer indirection.<\/li>\n<li>may have a deep derivation hierarchy.<\/li>\n<\/ul>\n<\/li>\n<li>Compile-Time Polymorphism\n<ul>\n<li>may generate a lengthy message in the error case, but using concepts such as <code>BasicLockable<\/code> in C++20 causes concise error messages.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>After this theoretical discussion, I will implement the strategized locking in both variations. The Strategized Locking supports, in my example, no-locking, exclusive locking, and shared locking. For simplicity reasons, I used internally already existing mutexes.<\/p>\n<h3>Run-Time Polymorphism<\/h3>\n<p>The program <code>strategizedLockingRuntime.cpp<\/code> presents three different locks.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ strategizedLockingRuntime.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;mutex&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;shared_mutex&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Lock<\/span> {                                     <em><span style=\"color: #0099ff;\">\/\/ (4)<\/span><\/em>\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">virtual<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\r\n    <span style=\"color: #006699; font-weight: bold;\">virtual<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">StrategizedLocking<\/span> {\r\n    Lock<span style=\"color: #555555;\">&amp;<\/span> lock;                                <em><span style=\"color: #0099ff;\"> \/\/ (1)<\/span><\/em>\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    StrategizedLocking(Lock<span style=\"color: #555555;\">&amp;<\/span> l)<span style=\"color: #555555;\">:<\/span> lock(l){      <em><span style=\"color: #0099ff;\"> \/\/ (2)<\/span><\/em>\r\n        lock.lock();\r\n    }\r\n    <span style=\"color: #555555;\">~<\/span>StrategizedLocking(){                      <em><span style=\"color: #0099ff;\">\/\/ (3)<\/span><\/em>\r\n        lock.unlock();\r\n    }\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> NullObjectMutex{\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock(){}\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock(){}\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">NoLock<\/span> <span style=\"color: #555555;\">:<\/span> <span style=\"color: #006699; font-weight: bold;\">public<\/span> Lock {                   <em><span style=\"color: #0099ff;\"> \/\/ (5)<\/span><\/em>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"NoLock::lock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        nullObjectMutex.lock();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"NoLock::unlock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n         nullObjectMutex.unlock();\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> NullObjectMutex nullObjectMutex;    <em><span style=\"color: #0099ff;\">\/\/ (10)<\/span><\/em>\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">ExclusiveLock<\/span> <span style=\"color: #555555;\">:<\/span> <span style=\"color: #006699; font-weight: bold;\">public<\/span> Lock {             <em><span style=\"color: #0099ff;\">\/\/ (6)<\/span><\/em>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    ExclusiveLock::lock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        mutex.lock();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    ExclusiveLock::unlock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        mutex.unlock();\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>mutex mutex;                   <em><span style=\"color: #0099ff;\">\/\/ (11)<\/span><\/em>\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">SharedLock<\/span> <span style=\"color: #555555;\">:<\/span> <span style=\"color: #006699; font-weight: bold;\">public<\/span> Lock {                <em><span style=\"color: #0099ff;\">\/\/ (7)<\/span><\/em>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        SharedLock::lock_shared: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        sharedMutex.lock_shared();             <em><span style=\"color: #0099ff;\">\/\/ (8)<\/span><\/em>\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        SharedLock::unlock_shared: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        sharedMutex.unlock_shared();           <em><span style=\"color: #0099ff;\">\/\/ (9)<\/span><\/em>\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>shared_mutex sharedMutex;     <em><span style=\"color: #0099ff;\">\/\/ (12)<\/span><\/em>\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    \r\n    NoLock noLock;\r\n    StrategizedLocking stratLock1{noLock};\r\n    \r\n    {\r\n        ExclusiveLock exLock;\r\n        StrategizedLocking stratLock2{exLock};\r\n        {\r\n            SharedLock sharLock;\r\n            StrategizedLocking startLock3{sharLock};\r\n        }\r\n    }\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The class <code>StrategizedLocking<\/code> has a <code>lock<\/code> (line 1). <code>StrategizedLocking<\/code> models scoped locking and, therefore, locks the mutex in the constructor (line 2) and unlocks it in the destructor (line 3). <code>Lock<\/code> (line 4) is an abstract class and defines all derived classes\u2019 interfaces. These are the classes <code>NoLock<\/code> (line 5), <code>ExclusiveLock<\/code> (line 6), and<code> SharedLock<\/code> (line 7). <code>SharedLock<\/code> invokes <code>lock_shared<\/code> (line 8) and <code>unlock_shared<\/code> (line 9) on its <code>std::shared_mutex<\/code>. Each of these locks holds one of the mutexes <code>NullObjectMutex<\/code> (line 10),<code> std::mutex<\/code> (line 11), or <code>std::shared_mutex<\/code> (line 12). <code>NullObjectMutex<\/code> is a <em>noop <\/em>placeholder. The mutexes are declared as <code>mutable<\/code>. Therefore, they are usable in constant member functions such as <code>lock<\/code> and <code>unlock<\/code>.<\/p>\n<h3>Compile-Time Polymorphism<\/h3>\n<p>The template-based implementation is quite similar to the object-oriented-based implementation. Instead of an abstract base class <code>Lock<\/code>, I define the concept <code>BasicLockable<\/code>. If you need more information about concepts, read my previous posts: <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/concepts\">concepts<\/a>.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\nconcept BasicLockable <span style=\"color: #555555;\">=<\/span> requires(T lo) {\r\n    lo.lock();\r\n    lo.unlock();\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><code>BasicLockable<\/code> requires from its type parameter <code>T<\/code> that it supports the member functions <code>lock<\/code> and <code>unlock<\/code>. Consequentially, the class template <code>StrategizedLocking<\/code> accepts only constraints type parameters:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span>BasicLockable Lock<span style=\"color: #555555;\">&gt;<\/span> \r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">StrategizedLocking<\/span> {\r\n...\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Finally, here is the template-based implementation.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ strategizedLockingCompileTime.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;mutex&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;shared_mutex&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\nconcept BasicLockable <span style=\"color: #555555;\">=<\/span> requires(T lo) {\r\n    lo.lock();\r\n    lo.unlock();\r\n};\r\n    \r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span>BasicLockable Lock<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">StrategizedLocking<\/span> {\r\n    Lock<span style=\"color: #555555;\">&amp;<\/span> lock;\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    StrategizedLocking(Lock<span style=\"color: #555555;\">&amp;<\/span> l)<span style=\"color: #555555;\">:<\/span> lock(l){\r\n        lock.lock();\r\n    }\r\n    <span style=\"color: #555555;\">~<\/span>StrategizedLocking(){\r\n        lock.unlock();\r\n    }\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> NullObjectMutex {\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock(){}\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock(){}\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">NoLock<\/span>{\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"NoLock::lock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        nullObjectMutex.lock();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"NoLock::unlock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n         nullObjectMutex.lock();\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> NullObjectMutex nullObjectMutex;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">ExclusiveLock<\/span> {\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    ExclusiveLock::lock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        mutex.lock();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    ExclusiveLock::unlock: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        mutex.unlock();\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>mutex mutex;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">SharedLock<\/span> {\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> lock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        SharedLock::lock_shared: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        sharedMutex.lock_shared();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> unlock() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        SharedLock::unlock_shared: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        sharedMutex.unlock_shared();\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>shared_mutex sharedMutex;\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    \r\n    NoLock noLock;\r\n    StrategizedLocking<span style=\"color: #555555;\">&lt;<\/span>NoLock<span style=\"color: #555555;\">&gt;<\/span> stratLock1{noLock};\r\n    \r\n    {\r\n        ExclusiveLock exLock;\r\n        StrategizedLocking<span style=\"color: #555555;\">&lt;<\/span>ExclusiveLock<span style=\"color: #555555;\">&gt;<\/span> stratLock2{exLock};\r\n        {\r\n            SharedLock sharLock;\r\n            StrategizedLocking<span style=\"color: #555555;\">&lt;<\/span>SharedLock<span style=\"color: #555555;\">&gt;<\/span> startLock3{sharLock};\r\n        }\r\n    }\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The programs <code>strategizedLockingRuntime.cpp<\/code> and <code>strategizedLockingCompileTime.cpp<\/code> produce the same output:<br \/><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6512\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/02\/strategizedLocking.png\" alt=\"strategizedLocking\" width=\"400\" height=\"358\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/02\/strategizedLocking.png 510w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/02\/strategizedLocking-300x269.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>The Thread-Safe Interface extends the critical section to an object&#8217;s interface. I will present it in my next post.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Locking is a classical way to protect a shared, mutable state. Today, I will present the two variants, Scoped Locking and Strategized Locking.<\/p>\n","protected":false},"author":21,"featured_media":6560,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[379],"tags":[430,433,402],"class_list":["post-6562","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-patterns","tag-lock","tag-mutex","tag-policy"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6562","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=6562"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6562\/revisions"}],"predecessor-version":[{"id":8136,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6562\/revisions\/8136"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/6560"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=6562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}