{"id":267,"date":"2016-03-04T09:18:46","date_gmt":"2016-03-04T09:18:46","guid":{"rendered":"http:\/\/www.crazygaze.com\/blog\/?p=267"},"modified":"2016-03-07T23:04:33","modified_gmt":"2016-03-07T23:04:33","slug":"boost-asio-thread-safety-and-reinventing-the-wheel","status":"publish","type":"post","link":"https:\/\/www.crazygaze.com\/blog\/2016\/03\/04\/boost-asio-thread-safety-and-reinventing-the-wheel\/","title":{"rendered":"Boost Asio, thread safety, and reinventing the wheel"},"content":{"rendered":"<p>I&#8217;ve been working on a new\u00a0network layer for my G4 project. (See\u00a0<a href=\"https:\/\/bitbucket.org\/ruifig\/g4devkit\">https:\/\/bitbucket.org\/ruifig\/g4devkit<\/a>\u00a0).<br \/>\nI ended up creating a library\u00a0with Windows IO Completion ports, which ended up being extremely similar to Boost Asio. So similar, that I considered just dropping my implementation and use Boost Asio instead of reinventing the wheel.\u00a0But as any good programmer knows, your\u00a0code is awesome and\u00a0anyone else&#8217;s code sucks, right?<\/p>\n<p id=\"AcKRsfj\"><img loading=\"lazy\" width=\"253\" height=\"137\" class=\"alignnone size-full wp-image-275 \" src=\"https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d864f1124f4.png\" alt=\"\" srcset=\"https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d864f1124f4.png 253w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d864f1124f4-100x54.png 100w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d864f1124f4-150x81.png 150w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d864f1124f4-200x108.png 200w\" sizes=\"(max-width: 253px) 100vw, 253px\" \/><\/p>\n<p>Of course that&#8217;s not true. Boost is an amazing library. But since\u00a0I was trying to keep the project&#8217;s dependencies to a minimum, I\u00a0kept working on my implementation.<\/p>\n<p>The thing is, Boost Asio is well designed, and even in instances where it seems it&#8217;s overcomplicating things, for example, by using way too many helper classes, it does so to solve specific\u00a0problems. Problems you don&#8217;t\u00a0realize are there until you try and create your own asynchronous network library.<\/p>\n<p>I started working on my implementation without looking too much into how Asio works internally. I just wanted a\u00a0similar\u00a0interface. How hard can it be? I just need something equivalent to\u00a0<a href=\"http:\/\/www.boost.org\/doc\/libs\/1_60_0\/doc\/html\/boost_asio\/reference\/io_service.html\" target=\"_blank\">asio::io_service<\/a> and <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_60_0\/doc\/html\/boost_asio\/reference\/ip__tcp\/socket.html\" target=\"_blank\">asio::tcp::socket<\/a>.<\/p>\n<p>My implementation worked well in the initial stages.\u00a0I even coded unit tests as I went along. Then, as I tested my new super awesome library with ever more complex unit tests, I started coming across design problems. Soon, I end up realizing that I needed functionality\u00a0to cancel asynchronous operations at a later time, so I could shutdown cleanly in some situations. Well, Boost Asio does that and more with\u00a0<a href=\"http:\/\/www.boost.org\/doc\/libs\/1_60_0\/doc\/html\/boost_asio\/reference\/deadline_timer.html\" target=\"_blank\">deadline_timer<\/a> . &#8220;Oh well, I thought&#8221;, I just need to code something similar to deadline_timer too.<\/p>\n<p>The &#8220;just one more thing I need&#8221; list kept growing&#8230;<\/p>\n<ul>\n<li>Why is\u00a0<a href=\"http:\/\/www.boost.org\/doc\/libs\/1_60_0\/doc\/html\/boost_asio\/reference\/ip__tcp\/acceptor.html\" target=\"_blank\"><span class=\"identifier\">tcp<\/span><span class=\"special\">::<\/span><span class=\"identifier\">acceptor<\/span><\/a>\u00a0used SOLELY\u00a0to accept connections, and not manage them ? Why not have a neat server class that nicely aggregates all the connections? Then, while you&#8217;re at it, make that a base server class because more OOP can only be a good thing, and have that base class\u00a0call your\u00a0virtual methods to get all your goodies?\n<ul>\n<li>It&#8217;s best not to try and guess what the application needs. The more the library has to guess, the more it ends up dealing with object lifetime issues, multithreading problems, or deadlocks that happen because you (a) need to protect data; and (b) in some cases you also need to call into application\u00a0code. Therefore the library can&#8217;t guess what the hell you&#8217;ll be doing in those callbacks\/virtuals.<\/li>\n<\/ul>\n<\/li>\n<li>Why are most Asio classes are not thread-safe? Surely you want everything to\u00a0be thread-safe in this age of multi-core madness!\n<ul>\n<li>Not really. Same as above. Better to not try to do\u00a0any\u00a0guesswork and leave that to the application.<\/li>\n<li>This one time at band camp, I tried to make my network library completely\u00a0thread-safe! That didn&#8217;t end up well. When you think everything is fine and your unit tests say so, you proudly decide to put your unit tests in a loop overnight, only to be greeted with a random crash or deadlock hours later. That&#8217;s fine. It&#8217;s just one more corner case you need to fix, right?<\/li>\n<\/ul>\n<\/li>\n<li>Why does Boost Asio guarantee that the handlers are called ONCE, and ONLY from a thread in which io_service::run (or run_one(), poll(), poll_one()) is being executed ?\n<ul>\n<li>Consistency. You don&#8217;t need to guess what will happen in most cases. A handler is aborted? You still get to know about it the same way you handle non-aborted handlers.<\/li>\n<\/ul>\n<\/li>\n<li>What\u00a0the hell do I need <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_60_0\/doc\/html\/boost_asio\/reference\/io_service__strand.html\" target=\"_blank\">io_service::strand<\/a> for?\n<ul>\n<li>So you don&#8217;t end up making a mess trying to create\u00a0thread-safe handlers.<\/li>\n<li>So you don&#8217;t end\u00a0up having all your IO threads blocked trying to serve the same connection, just because a specific handler for that connection decided to step out for a pint and leave the doors locked.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Creating non-trivial\u00a0thread-safe code is\u00a0always harder than it looks. This was me developing the previous network layer&#8230;<\/p>\n<p id=\"eMXihhl\"><img loading=\"lazy\" width=\"722\" height=\"270\" class=\"alignnone size-full wp-image-289 \" src=\"https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7.png\" alt=\"\" srcset=\"https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7.png 722w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-300x112.png 300w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-100x37.png 100w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-150x56.png 150w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-200x75.png 200w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-450x168.png 450w, https:\/\/www.crazygaze.com\/blog\/wp-content\/uploads\/2016\/03\/img_56d8c344c40e7-600x224.png 600w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/p>\n<p>In other words, there is no reason to reinvent the wheel. I&#8217;m sure I&#8217;ll have to add Boost as a dependency eventually, but because I&#8217;m stubborn, and I enjoy wasting\u00a0time creating solutions for problems that Boost Asio already solves, I&#8217;ll endure for now.<\/p>\n<p>In the next few posts I&#8217;ll dissect a couple of classes I had to create, which are the equivalents of \u00a0Boost&#8217;s strand, call_stack, deadline_timer &#8211; and possibly a few more.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been working on a new\u00a0network layer for my G4 project. (See\u00a0https:\/\/bitbucket.org\/ruifig\/g4devkit\u00a0). I ended up creating a library\u00a0with Windows IO Completion ports, which ended up being extremely similar to Boost Asio. So similar, that I considered just dropping my implementation and use Boost Asio instead of reinventing the wheel.\u00a0But as any good programmer knows, your\u00a0code [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[50],"tags":[14,12,45,10],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p7jpe0-4j","_links":{"self":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts\/267"}],"collection":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/comments?post=267"}],"version-history":[{"count":0,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/media?parent=267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/categories?post=267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/tags?post=267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}