{"id":6565,"date":"2023-05-22T07:50:01","date_gmt":"2023-05-22T07:50:01","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/dealing-with-mutation-thread-safe-interface\/"},"modified":"2023-08-23T17:04:57","modified_gmt":"2023-08-23T17:04:57","slug":"dealing-with-mutation-thread-safe-interface","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/dealing-with-mutation-thread-safe-interface\/","title":{"rendered":"Dealing with Mutation: Thread-Safe Interface"},"content":{"rendered":"<p>I continue my journey with concurrency patterns in today&#8217;s post. The Thread-Safe Interface fits very well when the critical sections are just objects.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<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>The naive idea to protect all member functions of a class with a lock causes, in the best case, a performance issue and, in the worst case, a deadlock.<\/p>\n<h2>A Deadlock<\/h2>\n<p>The small code snippet has a deadlock.<\/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;\">struct<\/span> Critical{\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> memberFunction1(){\r\n        lock(mut);\r\n        memberFunction2();\r\n    ...\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> memberFunction2(){\r\n        lock(mut);\r\n        ...\r\n    }\r\n\r\n    mutex mut;\r\n};\r\n\r\nCritical crit;\r\ncrit.memberFunction1();\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Calling<code> crit.memberFunction1<\/code> causes the mutex <code>mut<\/code> to be locked twice. For simplicity reasons, the lock is a scoped lock. Here are the two issues:<\/p>\n<ul>\n<li>When <code>lock<\/code> is a recursive lock, the second<code> lock(mut)<\/code> in <code>memberFunction2<\/code> is redundant.<\/li>\n<li>When <code>lock<\/code> is a non-recursive lock, the second<code> lock(mut)<\/code> in<code> memberFunction2<\/code> leads to undefined behavior. Most of the time, you get a deadlock.<\/li>\n<\/ul>\n<p>The thread-safe interface overcomes both issues.<\/p>\n<h2>The Thread-Safe Interface<\/h2>\n<p>Here is the straightforward idea of the Thread-Safe Interface.<\/p>\n<ul>\n<li>All interface member functions (<code>public<\/code>) use a lock.<\/li>\n<li>All implementation member functions (<code>protected<\/code> and <code>private<\/code>) must not use a lock.<\/li>\n<li>The interface member functions call only protected or private member functions but no public member functions.<\/li>\n<\/ul>\n<p>The following program shows the usage of the Thread-Safe Interface.<\/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;\">\/\/ threadSafeInterface.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;thread&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Critical<\/span>{\r\n\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> interface1() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lockGuard(mut);\r\n        implementation1();\r\n    }\r\n  \r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> interface2(){\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lockGuard(mut);\r\n        implementation2();\r\n        implementation3();\r\n        implementation1();\r\n    }\r\n   \r\n<span style=\"color: #9999ff;\">private:<\/span> \r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation1() <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;\">\"implementation1: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation2(){\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    implementation2: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation3(){    \r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        implementation3: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    }\r\n  \r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>mutex mut;                            <em><span style=\"color: #0099ff;\">\/\/ (1)\r\n<\/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    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1([]{ \r\n        <span style=\"color: #006699; font-weight: bold;\">const<\/span> Critical crit;\r\n        crit.interface1();\r\n    });\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2([]{\r\n        Critical crit;\r\n        crit.interface2();\r\n        crit.interface1();\r\n    });\r\n    \r\n    Critical crit;\r\n    crit.interface1();\r\n    crit.interface2();\r\n    \r\n    t1.join();\r\n    t2.join();    \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>Three threads, including the main thread, use instances of <code>Critical<\/code>. Thanks to the Thread-Safe Interface, all calls to the public API are synchronized. The mutex <code>mut<\/code> in line (1) is mutable and can be used in the constant member function <code>interface1<\/code>.<\/p>\n<p>The advantages of the thread-safe interface are threefold.<\/p>\n<ol>\n<li>A recursive call of a mutex is not possible. Recursive calls on a non-recursive mutex are undefined behavior in C++ and usually end in a deadlock.<\/li>\n<li>The program uses minimal locking and, therefore, minimal synchronization. Using just a <code>std::recursive_mutex<\/code> in each member function of the class <code>Critical<\/code> would end in more expensive synchronization.<\/li>\n<li>From the user&#8217;s perspective, <code>Critical<\/code> is straightforward to use because synchronization is only an implementation detail.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Each interface member function delegates its work to the corresponding implementation member function. The indirection overhead is a typical disadvantage of the Thread-Safe Interface.<\/p>\n<p>The output of the program shows the interleaving of the three threads.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6563\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterface.png\" alt=\"threadSafeInterface\" width=\"450\" height=\"317\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterface.png 504w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterface-300x211.png 300w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/p>\n<p>Although the Thread-Safe Interface seems easy to implement, there are two grave perils you have to keep in mind.<\/p>\n<\/p>\n<h3>Perils<\/h3>\n<p>Using a static member in your class or having virtual interfaces requires special care.<\/p>\n<h4>Static members<\/h4>\n<p>When your class has a static member that is not constant, you must synchronize all member function calls on the class instances.<\/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: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Critical<\/span>{\r\n    \r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> interface1() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lockGuard(mut);\r\n        implementation1();\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> interface2(){\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lockGuard(mut);\r\n        implementation2();\r\n        implementation3();\r\n        implementation1();\r\n    }\r\n    \r\n<span style=\"color: #9999ff;\">private:<\/span> \r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation1() <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;\">\"implementation1: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        <span style=\"color: #555555;\">++<\/span>called;\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation2(){\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"    implementation2: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        <span style=\"color: #555555;\">++<\/span>called;\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> implementation3(){    \r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"        implementation3: \"<\/span> \r\n                  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n        <span style=\"color: #555555;\">++<\/span>called;\r\n    }\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">inline<\/span> <span style=\"color: #006699; font-weight: bold;\">static<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span> called{<span style=\"color: #ff6600;\">0<\/span>};         <em><span style=\"color: #0099ff;\">\/\/ (1)<\/span><\/em>\r\n    <span style=\"color: #006699; font-weight: bold;\">inline<\/span> <span style=\"color: #006699; font-weight: bold;\">static<\/span> std<span style=\"color: #555555;\">::<\/span>mutex mut;\r\n\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Now, the class <code>Critical<\/code> has a static member <code>called<\/code> (line 32) to count how often the implementation functions were called. All instances of <code>Critical<\/code> use the same static member and have, therefore, to be synchronized. Since C++17, static data members can be declared inline. An inline static data member can be defined and initialized in the class definition.<\/p>\n<h4>Virtuality<\/h4>\n<p>When you override a virtual interface function, the overriding function should have a lock even if the function is private.<\/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;\">\/\/ threadSafeInterfaceVirtual.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;thread&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Base<\/span>{\r\n    \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> interface() {\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lockGuard(mut);\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Base with lock\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    }\r\n    <span style=\"color: #006699; font-weight: bold;\">virtual<\/span> <span style=\"color: #555555;\">~<\/span>Base() <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;\r\n<span style=\"color: #9999ff;\">private:<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>mutex mut;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Derived<\/span><span style=\"color: #555555;\">:<\/span> <span style=\"color: #006699; font-weight: bold;\">public<\/span> Base{\r\n\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> interface() override {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Derived without lock\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\r\n    }\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    Base<span style=\"color: #555555;\">*<\/span> base1 <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">new<\/span> Derived;\r\n    base1<span style=\"color: #555555;\">-&gt;<\/span>interface();\r\n\r\n    Derived der;\r\n    Base<span style=\"color: #555555;\">&amp;<\/span> base2 <span style=\"color: #555555;\">=<\/span> der;\r\n    base2.interface();\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>In the calls, <code>base1-&gt;interface<\/code> and <code>base2.interface<\/code> the static type of <code>base1<\/code> and <code>base2<\/code> is <code>Base,<\/code> and, therefore, the <code>interface<\/code> is accessible. Because the interface member function is virtual, the call happens at run time using the dynamic type <code>Derived<\/code>. At last, the private member function <code>interface<\/code> of the class <code>Derived<\/code> is invoked.<\/p>\n<p>The program&#8217;s output shows the unsynchronized invocation of Derived&#8217;s interface function.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6564\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterfaceVirtual.png\" alt=\"threadSafeInterfaceVirtual\" width=\"500\" height=\"230\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterfaceVirtual.png 504w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/05\/threadSafeInterfaceVirtual-300x138.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>There are two typical ways to overcome this issue.<\/p>\n<ol>\n<li>Make the member function interface a non-virtual member function. This technique is called NVI (Non-Virtual Interface). The non-virtual member function guarantees that the interface function of the base class <code>Base<\/code> is used. Additionally, overriding the interface function using <code>override<\/code> causes a compile-time error because there is nothing to override.<\/li>\n<li>Declare the member function interface as <code>final<\/code>: <code>virtual void interface() final<\/code>. Thanks to <code>final<\/code>, overriding an as <code>final<\/code> declared virtual member function causes a compile-time error.<\/li>\n<\/ol>\n<p>Although I presented two ways to overcome the challenges of virtuality, I strongly suggest using the NVI idiom. Use early binding if you don\u2019t need late binding (virtuality). You can read more about NVI in my post:<a href=\"https:\/\/www.modernescpp.com\/index.php\/the-template-method\">The Template Method<\/a>.<\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>Guarded Suspension applies a different strategy to deal with mutation. It signals when it is done with its mutation. In my next post, I will write about Guarded Suspension.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I continue my journey with concurrency patterns in today&#8217;s post. The Thread-Safe Interface fits very well when the critical sections are just objects.<\/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":[],"class_list":["post-6565","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-patterns"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6565","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=6565"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6565\/revisions"}],"predecessor-version":[{"id":8137,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6565\/revisions\/8137"}],"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=6565"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6565"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6565"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}