{"id":4325,"date":"2021-09-01T14:10:25","date_gmt":"2021-09-01T12:10:25","guid":{"rendered":"https:\/\/mariusbancila.ro\/blog\/?p=4325"},"modified":"2021-09-01T14:10:28","modified_gmt":"2021-09-01T12:10:28","slug":"synchronized-output-streams-in-c20","status":"publish","type":"post","link":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/","title":{"rendered":"Synchronized output streams in C++20"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">One of the many things included in C++20 is the support for synchronizing output streams for operations that may have race conditions. To understand the problem let&#8217;s begin with the following example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::vector&lt;std::jthread> threads;\n   for (int i = 1; i &lt;= 10; ++i)\n   {\n      threads.push_back(\n         std::jthread([](const int id)\n            {\n               std::cout &lt;&lt; \"I am thread [\" &lt;&lt; id &lt;&lt; \"]\" &lt;&lt; '\\n';\n            }, i));\n   }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We are starting a bunch of threads and what they do is printing a text to the console and then terminate. So you would expect an output like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">I am thread [4]\nI am thread [3]\nI am thread [8]\nI am thread [5]\nI am thread [9]\nI am thread [6]\nI am thread [10]\nI am thread [7]\nI am thread [2]\nI am thread [1]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You cannot expect the threads to execute in the order they were started but the intention is to have an output like the one above. However, it turns out that what you get is rather scrambled text like the following:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">I am thread [I am thread [4I am thread [2I am thread [7]I am thread [9]\nI am thread [3]\n\nI am thread [5]\nI am thread [10]I am thread [8]\nI am thread [6]\n]\n]\n1]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The following example does not exhibit this problem. Let&#8217;s take a look:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::vector&lt;std::jthread> threads;\n\n   auto worker = [](std::string text) { std::cout &lt;&lt; text; };\n   auto names = { \"Alpha\", \"Beta\", \"Gamma\", \"Delta\", \"Epsilon\" };\n\n   using namespace std::string_literals;\n   for (auto const&amp; name : names)\n      threads.push_back(std::jthread(worker, \"Hello, \"s + name + \"!\\n\"));\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No matter how many times you run this code it always shows the output in the following form:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Hello, Alpha!\nHello, Delta!\nHello, Gamma!\nHello, Beta!\nHello, Epsilon!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In both these examples I used <code>std::cout<\/code> to print to the output console. Obviously, there are data races that occur in the first example but not in the second. However, <code>std::cout<\/code> is guaranteed to be thread-safe (unless <code>sync_with_stdio(false)<\/code> has been called). The use of the <code>operator&lt;&lt;<\/code> is fine, as we can see in the second example. But multiple calls to this <code>operator&lt;&lt;<\/code> are not atomic and they can be interrupted and resumed after the thread resumes its execution. So if we take the line <code>std::cout &lt;&lt; \"I am thread [\" &lt;&lt; id &lt;&lt; \"]\" &lt;&lt; '\\n';<\/code> there are four calls to <code>operator&lt;&lt;<\/code>. So the execution can stop between any of these and other thread will write to the output. So the output can have any of these forms:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>I am thread [1]\\nI am thread [2]\\n<\/code><\/li><li><code>I am thread[I am thread[2]\\n1]\\n<\/code><\/li><li><code>I am thread[1I am thread]\\n[2]\\n<\/code><\/li><li>etc. etc.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This means that you can solve this problem by writing to an output string stream and after having all the text that should be atomically written to the console using the <code>std::cout<\/code> object. This is shown in the following example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::vector&lt;std::jthread> threads;\n   for (int i = 1; i &lt;= 10; ++i)\n   {\n      threads.push_back(\n         std::jthread([](const int id)\n            {\n               std::stringstream s;\n               s &lt;&lt; \"I am thread [\" &lt;&lt; id &lt;&lt; \"]\" &lt;&lt; '\\n';\n               std::cout &lt;&lt; s.str();\n            }, i));\n   }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In C++20, there is a simpler solution: <code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/io\/basic_osyncstream\">std::basic_osyncstream<\/a><\/code> (available in the new <code>&lt;syncstream><\/code> header) which provides the means for multiple threads to write to the same output stream in a synchronized way. Changes to the first example that had data races are minimal, but can have two forms:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>using a named variable<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::vector&lt;std::jthread> threads;\n   for (int i = 1; i &lt;= 10; ++i)\n   {\n      threads.push_back(\n         std::jthread([](const int id)\n            {\n               std::osyncstream scout{ std::cout };\n               scout &lt;&lt; \"I am thread [\" &lt;&lt; id &lt;&lt; \"]\" &lt;&lt; '\\n';\n            }, i));\n   }\n}<\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>using a temporary object<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::vector&lt;std::jthread> threads;\n   for (int i = 1; i &lt;= 10; ++i)\n   {\n      threads.push_back(\n         std::jthread([](const int id)\n            {\n               std::osyncstream { std::cout } &lt;&lt; \"I am thread [\" &lt;&lt; id &lt;&lt; \"]\" &lt;&lt; '\\n';\n            }, i));\n   }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note<\/strong>: There are two specializations of <code>std::basic_osyncstream<\/code> for the common character types, <code>std::osyncstream<\/code> for <code>char<\/code> (that we saw in the previous snippet) and <code>std::wosyncstream<\/code> for <code>wchar_t<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As long as all the writes to the same destination buffer (such as the standard output in this example) are written through instances of the <code>std::basic_osyncstream<\/code> class, it is guaranteed that these write operations are free of data races. The way this works is that <code>std::basic_osyncstream<\/code> wraps the output stream but also contains an internal buffer (of type <code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/io\/basic_syncbuf\">std::basic_syncbuf<\/a><\/code>) that accumulates the output, where it appears as a contiguous sequence of characters. Upon destruction, or when explicitly calling the <code>emit()<\/code> method, the content of the internal sync buffer is transferred to the wrapped stream. Let&#8217;s see some examples to understand how this works.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::ostringstream str{ };\n   {\n      std::osyncstream syncstr{ str };\n      syncstr &lt;&lt; \"Hello, World!\";\n\n      std::cout &lt;&lt; \"[1]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n   }\n\n   std::cout &lt;&lt; \"[2]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, <code>str<\/code> is a <code>std::ostringstream<\/code>. <code>syncstr<\/code> is a <code>std::osyncstream<\/code> that wraps this string stream. We are writing to the synced stream. At point <code>[1]<\/code>, calling the <code>str()<\/code> method of <code>ostringstream<\/code> will return an empty string, because the sync stream has not emitted the content of its internal buffer to the wrapped stream. That happens after the <code>syncstr<\/code> object is destroyed as it goes out of scope. Therefore, at point <code>[2]<\/code>, <code>str<\/code> will contain the written text. The output is, therefore, as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[1]:\n[2]:Hello, World!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We can also explicitly call <code>emit()<\/code> to transfer the content of the internal buffer to the wrapped output stream. The following example demonstrates this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::ostringstream str{ };\n   {\n      std::osyncstream syncstr{ str };\n      syncstr &lt;&lt; \"Hello, World!\";\n\n      std::cout &lt;&lt; \"[1]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n\n      syncstr.emit();\n\n      std::cout &lt;&lt; \"[2]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n\n      syncstr &lt;&lt; \"Hello, all!\";\n\n      std::cout &lt;&lt; \"[3]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n   }\n\n   std::cout &lt;&lt; \"[4]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What happens here is that:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>at point <code>[1]<\/code>, nothing has been emitted, so the content of the <code>ostringstream<\/code> is empty.<\/li><li>at point <code>[2]<\/code> the string stream will contain the &#8220;Hello, World!&#8221; text since a call to <code>emit()<\/code> previously occurred<\/li><li>at point <code>[3]<\/code> the string stream contains only &#8220;Hello, World!&#8221; even though more text has been written to the sync output stream previously<\/li><li>at point <code>[4]<\/code> the string stream contains &#8220;Hello, World!Hello, all!&#8221; since the sync output stream emitted the rest of its internal buffer upon going out of scope.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The output is as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[1]:\n[2]:Hello, World!\n[3]:Hello, World!\n[4]:Hello, World!Hello, all!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can also get a pointer to the wrapped stream of a <code>std::basic_osyncstream<\/code> with a call to <code>get_wrapped()<\/code>. This can be used to sequence content to the same stream from multiple instances of <code>std::basic_osyncstream<\/code>. Here is an example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main()\n{\n   std::ostringstream str{ };\n   {\n      std::osyncstream syncstr{ str };\n      syncstr &lt;&lt; \"Hello, World!\";\n\n      std::cout &lt;&lt; \"[1]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n\n      {\n         std::osyncstream syncstr2{ syncstr.get_wrapped() };\n         syncstr2 &lt;&lt; \"Hello, all!\";\n\n         std::cout &lt;&lt; \"[2]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n      }\n\n      std::cout &lt;&lt; \"[3]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n   }\n\n   std::cout &lt;&lt; \"[4]:\" &lt;&lt; str.str() &lt;&lt; '\\n';\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this snippet we have two <code>std::osyncstream<\/code> objects, with different scopes, both wrapping the same string stream. What happens is that:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>at point <code>[1]<\/code>, <code>str<\/code> is empty because <code>syncstr<\/code> has not emitted its content<\/li><li>at point <code>[2]<\/code>, <code>str<\/code> is still empty because neither <code>syncstr<\/code> nor <code>syncstr2<\/code> have emitted their content<\/li><li>at point <code>[3]<\/code>, <code>str<\/code> contains the text &#8220;Hello, all!&#8221; because <code>syncstr2<\/code> has gone out of scope and therefore emitted its internal content<\/li><li>at point <code>[4]<\/code>, <code>str<\/code> contains the text &#8220;Hello, all!Hello, World!&#8221; because <code>syncstr<\/code> has also gone out of scope and therefore emitted its internal content<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The output for this example is the following:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[1]:\n[2]:\n[3]:Hello, all!\n[4]:Hello, all!Hello, World!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>std::osyncstream<\/code> is a C++20 standard alternative to explicitly using synchronization mechanisms (such as <code>std::mutex<\/code>) for writing content to output streams in a data race-free manner.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the many things included in C++20 is the support for synchronizing output streams for operations that may have race conditions.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[7],"tags":[451,543,194,638],"class_list":["post-4325","post","type-post","status-publish","format-standard","hentry","category-c","tag-c","tag-c20","tag-concurrency","tag-streams"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Marius Bancila\"\/>\n\t<meta name=\"keywords\" content=\"c++,c++20,concurrency,streams\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Marius Bancila&#039;s Blog | About code. Mostly on C++\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Synchronized output streams in C++20\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2021-09-01T12:10:25+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2021-09-01T12:10:28+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Synchronized output streams in C++20\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#article\",\"name\":\"Synchronized output streams in C++20\",\"headline\":\"Synchronized output streams in C++20\",\"author\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\"},\"datePublished\":\"2021-09-01T14:10:25+02:00\",\"dateModified\":\"2021-09-01T14:10:28+02:00\",\"inLanguage\":\"en-US\",\"commentCount\":1,\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#webpage\"},\"articleSection\":\"C++, C++, c++20, concurrency, streams\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"name\":\"IT\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"position\":2,\"name\":\"IT\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"name\":\"Software\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"position\":3,\"name\":\"Software\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/c\\\/#listItem\",\"name\":\"C++\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"name\":\"IT\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/c\\\/#listItem\",\"position\":4,\"name\":\"C++\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/c\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#listItem\",\"name\":\"Synchronized output streams in C++20\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"name\":\"Software\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#listItem\",\"position\":5,\"name\":\"Synchronized output streams in C++20\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/c\\\/#listItem\",\"name\":\"C++\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\",\"name\":\"Marius Bancila's Blog\",\"description\":\"About code. Mostly on C++\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/\",\"name\":\"Marius Bancila\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a84dd2831d955c38355ddea55df4df260809b88f36408bc14fd4eab8f7f131c9?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Marius Bancila\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#webpage\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/\",\"name\":\"Synchronized output streams in C++20\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2021\\\/09\\\/01\\\/synchronized-output-streams-in-c20\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"datePublished\":\"2021-09-01T14:10:25+02:00\",\"dateModified\":\"2021-09-01T14:10:28+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/\",\"name\":\"Marius Bancila's Blog\",\"description\":\"About code. Mostly on C++\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Synchronized output streams in C++20","description":"","canonical_url":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/","robots":"max-image-preview:large","keywords":"c++,c++20,concurrency,streams","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#article","name":"Synchronized output streams in C++20","headline":"Synchronized output streams in C++20","author":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"publisher":{"@id":"https:\/\/mariusbancila.ro\/blog\/#organization"},"datePublished":"2021-09-01T14:10:25+02:00","dateModified":"2021-09-01T14:10:28+02:00","inLanguage":"en-US","commentCount":1,"mainEntityOfPage":{"@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#webpage"},"isPartOf":{"@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#webpage"},"articleSection":"C++, C++, c++20, concurrency, streams"},{"@type":"BreadcrumbList","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog#listItem","position":1,"name":"Home","item":"https:\/\/mariusbancila.ro\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","name":"IT"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","position":2,"name":"IT","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","name":"Software"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","position":3,"name":"Software","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/#listItem","name":"C++"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","name":"IT"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/#listItem","position":4,"name":"C++","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#listItem","name":"Synchronized output streams in C++20"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","name":"Software"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#listItem","position":5,"name":"Synchronized output streams in C++20","previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/#listItem","name":"C++"}}]},{"@type":"Organization","@id":"https:\/\/mariusbancila.ro\/blog\/#organization","name":"Marius Bancila's Blog","description":"About code. Mostly on C++","url":"https:\/\/mariusbancila.ro\/blog\/"},{"@type":"Person","@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author","url":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/","name":"Marius Bancila","image":{"@type":"ImageObject","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/a84dd2831d955c38355ddea55df4df260809b88f36408bc14fd4eab8f7f131c9?s=96&d=mm&r=g","width":96,"height":96,"caption":"Marius Bancila"}},{"@type":"WebPage","@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#webpage","url":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/","name":"Synchronized output streams in C++20","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/mariusbancila.ro\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/#breadcrumblist"},"author":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"creator":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"datePublished":"2021-09-01T14:10:25+02:00","dateModified":"2021-09-01T14:10:28+02:00"},{"@type":"WebSite","@id":"https:\/\/mariusbancila.ro\/blog\/#website","url":"https:\/\/mariusbancila.ro\/blog\/","name":"Marius Bancila's Blog","description":"About code. Mostly on C++","inLanguage":"en-US","publisher":{"@id":"https:\/\/mariusbancila.ro\/blog\/#organization"}}]},"og:locale":"en_US","og:site_name":"Marius Bancila's Blog | About code. Mostly on C++","og:type":"article","og:title":"Synchronized output streams in C++20","og:url":"https:\/\/mariusbancila.ro\/blog\/2021\/09\/01\/synchronized-output-streams-in-c20\/","article:published_time":"2021-09-01T12:10:25+00:00","article:modified_time":"2021-09-01T12:10:28+00:00","twitter:card":"summary","twitter:title":"Synchronized output streams in C++20"},"aioseo_meta_data":{"post_id":"4325","title":null,"description":null,"keywords":[],"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":[],"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":{"id":"aioseo-article-6369669019c63","slug":"article","graphName":"Article","label":"Article","properties":{"type":"BlogPosting","name":"#post_title","headline":"#post_title","description":"#post_excerpt","image":"","keywords":"","author":{"name":"#author_name","url":"#author_url"},"dates":{"include":true,"datePublished":"","dateModified":""}}},"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":"{\"article\":{\"articleType\":\"BlogPosting\"},\"course\":{\"name\":\"\",\"description\":\"\",\"provider\":\"\"},\"faq\":{\"pages\":[]},\"product\":{\"reviews\":[]},\"recipe\":{\"ingredients\":[],\"instructions\":[],\"keywords\":[]},\"software\":{\"reviews\":[],\"operatingSystems\":[]},\"webPage\":{\"webPageType\":\"WebPage\"}}","pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","location":null,"local_seo":{"locations":{"business":{"name":"","businessType":"","image":"","areaServed":"","urls":{"website":"","aboutPage":"","contactPage":""},"address":{"streetLine1":"","streetLine2":"","zipCode":"","city":"","state":"","country":"","addressFormat":"#streetLineOne\n#streetLineTwo\n#city, #state #zipCode"},"contact":{"email":"","phone":"","phoneFormatted":"","fax":"","faxFormatted":""},"ids":{"vat":"","tax":"","chamberOfCommerce":""},"payment":{"priceRange":"","currenciesAccepted":"","methods":""}}},"openingHours":{"useDefaults":true,"show":true,"alwaysOpen":false,"use24hFormat":false,"timezone":"","labels":{"closed":"","alwaysOpen":""},"days":{"monday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"tuesday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"wednesday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"thursday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"friday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"saturday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"},"sunday":{"open24h":false,"closed":false,"openTime":"09:00","closeTime":"17:00"}}}},"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2021-09-01 09:41:47","updated":"2025-12-12 07:56:25","seo_analyzer_scan_date":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"author_meta":{"display_name":"Marius Bancila","author_link":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/"},"featured_img":null,"jetpack_publicize_connections":[],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Marius Bancila","author_link":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/"},"uagb_comment_info":1,"uagb_excerpt":"One of the many things included in C++20 is the support for synchronizing output streams for operations that may have race conditions.","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">C++<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">C++<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">C++<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">c++20<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">concurrency<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">streams<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">C++<\/span>","<span class=\"advgb-post-tax-term\">c++20<\/span>","<span class=\"advgb-post-tax-term\">concurrency<\/span>","<span class=\"advgb-post-tax-term\">streams<\/span>"]}},"comment_count":"1","relative_dates":{"created":"Posted 5 years ago","modified":"Updated 5 years ago"},"absolute_dates":{"created":"Posted on September 1, 2021","modified":"Updated on September 1, 2021"},"absolute_dates_time":{"created":"Posted on September 1, 2021 2:10 pm","modified":"Updated on September 1, 2021 2:10 pm"},"featured_img_caption":"","series_order":"","jetpack_shortlink":"https:\/\/wp.me\/pYNdv-17L","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/4325","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/comments?post=4325"}],"version-history":[{"count":8,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/4325\/revisions"}],"predecessor-version":[{"id":4333,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/4325\/revisions\/4333"}],"wp:attachment":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/media?parent=4325"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/categories?post=4325"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/tags?post=4325"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}