{"id":4506,"date":"2018-11-29T17:55:03","date_gmt":"2018-11-29T23:55:03","guid":{"rendered":"http:\/\/neosmart.net\/blog\/?p=4506"},"modified":"2018-12-04T12:11:38","modified_gmt":"2018-12-04T18:11:38","slug":"rsevents-manual-and-auto-reset-events-for-rust","status":"publish","type":"post","link":"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/","title":{"rendered":"rsevents: manual and auto reset events for rust"},"content":{"rendered":"<p><a href=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo.png\" rel=\"follow\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-thumbnail wp-image-4454 colorbox-4506\" src=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-150x150.png\" alt=\"\" width=\"150\" height=\"150\" srcset=\"https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-150x150.png 150w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-600x600.png 600w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo-300x300.png 300w, https:\/\/neosmart.net\/blog\/wp-content\/uploads\/rust-logo.png 1024w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><\/a>One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts of threads with <code>sync<\/code>\u00a0and <code>send<\/code>) and the presence of various structures in the standard library aimed at simplifying development of correct, multithreaded code.<\/p>\n<p><code><a href=\"https:\/\/github.com\/neosmart\/rsevents\">rsevents<\/a><\/code>\u00a0is a new crate that should be immediately familiar to anyone that has done multithreaded programming under Windows: it exposes a synchronization <em>primitive<\/em>, namely, an <code>event<\/code>\u00a0for use where <code>Mutex<\/code>\u00a0&#8211; intended to exclusively marshall access to a variable or region of code &#8211; either does not convey the correct semantics or is not the right tool for the job. For those that didn&#8217;t come fleeing to rust from a Win32 background, in Windows an <code>event<\/code>\u00a0is the lowest-level kernel synchronization primitive, which can be thought of as a &#8220;waitable <code>bool<\/code>&#8221; &#8211; it is either <code>set<\/code>\u00a0or <code>reset<\/code>\u00a0(on or off, true or false) and if it isn&#8217;t set, you can wait on it until it becomes set.<\/p>\n<p><!--more--><\/p>\n<p>An event is used for (unstructured) synchronization of state, a lot like an anonymous, 1-bit\u00a0<code>Channel<\/code>\u00a0but simultaneously much more flexible (but trickier!) as it is a primitive. To naively implement events in rust (<a href=\"https:\/\/neosmart.net\/blog\/2015\/pevents-a-cross-platform-win32-events-library\/\" rel=\"follow\">or in posix<\/a>), it would be the equivalent of a conditional variable and a mutex, where the mutex is used only to protect the integrity of the conditional variable (and not to otherwise indicate a critical section), only without spurious wakes. Win32 events (and <code>rsevents<\/code>) come in two different variants, a so-called &#8220;manual reset&#8221; event and the (undoubtedly more important) &#8220;auto reset&#8221; event. To continue with the posix parallel, the behavior is the difference between using <code>pthread_cond_broadcast<\/code> and <code>pthread_cond_signal<\/code>\u00a0&#8211; it either wakes up all waiting listeners or only one, thereby guaranteeing atomicity.<\/p>\n<p><code>rsevents<\/code>\u00a0implements these as <code><a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/struct.AutoResetEvent.html\">rsevents::AutoResetEvent<\/a><\/code>\u00a0and <a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/struct.ManualResetEvent.html\" rel=\"nofollow\"><code>rsevents::ManualResetEvent<\/code><\/a>, both <code>impl<\/code>s of the trait <code><a href=\"https:\/\/docs.rs\/rsevents\/0.2.0\/rsevents\/trait.Awaitable.html\">rsevents::Awaitable<\/a><\/code>, atop of the excellent <code>ParkingLot<\/code>\u00a0crate for the best sleep\/wake performance rust currently has to offer, with minimal overhead to boot. <a href=\"https:\/\/docs.rs\/rsevents\/\" rel=\"nofollow\">As the docs illustrate<\/a>, they are dead-simple to use and allow one to quickly get started with easily polling or awaiting state changes:<\/p>\n<pre><code class=\"language-rust\">\/\/ create a new, initially unset event\r\nlet event = AutoResetEvent::new(State::Unset);\r\n\r\n\/\/ and wrap it in an ARC to allow sharing across thread boundaries\r\nlet event = Arc::new(event);\r\n\r\n\/\/ create a worker thread to complete some task\r\n{\r\n\tlet shared = event.clone();\r\n\tstd::thread::spawn(|| {\r\n\t\t\/\/ perform some task\r\n\t\t...\r\n\t\t\/\/ and signal to ONE waiting thread that the result is ready\r\n\t\tshared.set();\r\n\t});\r\n}\r\n\r\n...\r\n\r\n\/\/ wait for the spawned thread to finish the queued work\r\nevent.wait();\r\n<\/code><\/pre>\n<p><code>rsevents<\/code>\u00a0only represents the core underpinnings of event-based synchronization &#8211; as mentioned repeatedly, these are\u00a0<em>synchronization primitives<\/em> and while they may be useful on their own to communicate changes in (one-bit) state,<sup id=\"rf1-4506\"><a href=\"#fn1-4506\" title=\"or to even implement crude critical sections, if you were mad enough\" rel=\"footnote\">1<\/a><\/sup> they are actually more useful to create <code>Awaitable<\/code>\u00a0objects (hence the separation between the events and the <code>Awaitable<\/code>\u00a0interface). This is where the true power of <code>rsevents<\/code>\u00a0is exposed: it lets you build (or return) objects on top of the events, which become asynchronously awaitable.<sup id=\"rf2-4506\"><a href=\"#fn2-4506\" title=\"Not to be confused with async\/await&nbsp;which does the same but only as part of what is basically an event loop\" rel=\"footnote\">2<\/a><\/sup><\/p>\n<p>To get the ball rolling, a separate crate is also being introducing: <code>rsevents-extra<\/code>\u00a0which contains helpful synchronization objects built atop of <code>rsevents<\/code>\u00a0all of which implement <code>rsevents::Awaitable<\/code>. One example of an object implementing such behavior is <code><a href=\"https:\/\/docs.rs\/rsevents\/0.1.0\/rsevents_extra\/struct.CountdownEvent.html\">CountdownEvent<\/a><\/code>\u00a0which implements an awaitable reverse counter that can be used to wait until\u00a0<em>n<\/em> tasks have finished: you initialize it some value, decrement it (calling <code>CountdownEvent::tick()<\/code>) until it reaches zero, at which point any threads waiting on the object (via <code>CountdownEvent::wait()<\/code>, courtesy of <code>rsevents::Awaitable<\/code>) are awoken:<\/p>\n<pre><code class=\"language-rust\">let countdown = CountdownEvent::new(42);\r\n\r\nthread::scope(|scope| {\r\n    let worker_thread = scope.spawn(|_| {\r\n        println!(\"Worker thread reporting for duty!\");\r\n\r\n        \/\/ block here until all the countdown has elapsed\r\n        countdown.wait();\r\n\r\n        println!(\"Worker thread can now do something because the countdown finished!\");\r\n    });\r\n\r\n    for i in 0..1000 {\r\n        if i % 7 == 3 {\r\n            countdown.tick();\r\n        }\r\n    }\r\n});\r\n\r\n<\/code><\/pre>\n<p>It&#8217;s a pretty silly example that doesn&#8217;t do the crate justice, but countdown events are a great way of performantly waiting for an external event predicated on <em>n<\/em> things taking place, and will outperform other alternatives that involve mutating shared state, while simultaneously abstracting away the process of <em>actually waiting<\/em> on the state to change.<\/p>\n<p>In my days of Win32 C\/C++ programming, I had written an entire library of single-file headers each implementing a different synchronization model and built directly atop of auto or manual reset events. Rust has obviated quite a few of them, but there&#8217;s a lot to be said for the flexibility that events have to offer (and their very favorable performance characteristics). <code>rsevents-extra<\/code>\u00a0is intended to be a community project and <a href=\"https:\/\/github.com\/neosmart\/rsevents-extra\/pulls\" rel=\"nofollow\">is accepting pull requests<\/a> for other useful synchronization objects implementing <code>Awaitable<\/code>, so if you have any good ideas, we&#8217;re listening!<\/p>\n<hr class=\"footnotes\"><ol class=\"footnotes\"><li id=\"fn1-4506\"><p>or to even implement crude critical sections, if you were mad enough&nbsp;<a href=\"#rf1-4506\" class=\"backlink\" title=\"Jump back to footnote 1 in the text.\">&#8617;<\/a><\/p><\/li><li id=\"fn2-4506\"><p>Not to be confused with <code>async<\/code>\/<code>await<\/code>\u00a0which does the same but only as part of what is basically an event loop&nbsp;<a href=\"#rf2-4506\" class=\"backlink\" title=\"Jump back to footnote 2 in the text.\">&#8617;<\/a><\/p><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>One of the unique characteristics of Rust (both the language and the community that has evolved around it) is a strong acknowledgement of multithreading, synchronization, and concurrency, as witnessed in the design of the core language (which acknowledges OS concepts &hellip; <a href=\"https:\/\/neosmart.net\/blog\/rsevents-manual-and-auto-reset-events-for-rust\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":505,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[989,52,11,993,936],"class_list":["post-4506","post","type-post","status-publish","format-standard","hentry","category-software","tag-crate","tag-open-source","tag-programming","tag-rsevents","tag-rust"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4xDa-1aG","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/users\/505"}],"replies":[{"embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/comments?post=4506"}],"version-history":[{"count":8,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506\/revisions"}],"predecessor-version":[{"id":4514,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/posts\/4506\/revisions\/4514"}],"wp:attachment":[{"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/media?parent=4506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/categories?post=4506"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/neosmart.net\/blog\/wp-json\/wp\/v2\/tags?post=4506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}