mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-01-17 14:32:54 +00:00
544 lines
34 KiB
HTML
544 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<meta name="description" content="API documentation for the Rust `chan` crate.">
|
||
<meta name="keywords" content="rust, rustlang, rust-lang, chan">
|
||
|
||
<title>chan - Rust</title>
|
||
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../main.css" id="themeStyle">
|
||
<script src="../storage.js"></script>
|
||
|
||
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc mod">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
|
||
<nav class="sidebar">
|
||
<div class="sidebar-menu">☰</div>
|
||
|
||
<p class='location'>Crate chan</p><div class="sidebar-elems"><div class="block items"><ul><li><a href="#macros">Macros</a></li><li><a href="#structs">Structs</a></li><li><a href="#functions">Functions</a></li></ul></div><p class='location'></p><script>window.sidebarCurrent = {name: 'chan', ty: 'mod', relpath: '../'};</script></div>
|
||
</nav>
|
||
|
||
<div class="theme-picker">
|
||
<button id="theme-picker" aria-label="Pick another theme!">
|
||
<img src="../brush.svg" width="18" alt="Pick another theme!">
|
||
</button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<script src="../theme.js"></script>
|
||
<nav class="sub">
|
||
<form class="search-form js-only">
|
||
<div class="search-container">
|
||
<input class="search-input" name="search"
|
||
autocomplete="off"
|
||
placeholder="Click or press ‘S’ to search, ‘?’ for more options…"
|
||
type="search">
|
||
</div>
|
||
</form>
|
||
</nav>
|
||
|
||
<section id='main' class="content">
|
||
<h1 class='fqn'><span class='in-band'>Crate <a class="mod" href=''>chan</a></span><span class='out-of-band'><span id='render-detail'>
|
||
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
|
||
[<span class='inner'>−</span>]
|
||
</a>
|
||
</span><a class='srclink' href='../src/chan/lib.rs.html#1-1760' title='goto source code'>[src]</a></span></h1>
|
||
<div class='docblock'><p>This crate provides an implementation of a multi-producer, multi-consumer
|
||
channel. Channels come in three varieties:</p>
|
||
<ol>
|
||
<li>Asynchronous channels. Sends never block. Its buffer is only limited by the
|
||
available resources on the system.</li>
|
||
<li>Synchronous buffered channels. Sends block when the buffer is full. The
|
||
buffer is depleted by receiving on the channel.</li>
|
||
<li>Rendezvous channels (synchronous channels without a buffer). Sends block
|
||
until a receive has consumed the value sent. When a sender and receiver
|
||
synchronize, they are said to <em>rendezvous</em>.</li>
|
||
</ol>
|
||
<p>Asynchronous channels are created with <code>chan::async()</code>. Synchronous channels
|
||
are created with <code>chan::sync(k)</code> where <code>k</code> is the buffer size. Rendezvous
|
||
channels are created with <code>chan::sync(0)</code>.</p>
|
||
<p>All channels are split into the same two types upon creation: a <code>Sender</code> and
|
||
a <code>Receiver</code>. Additional senders and receivers can be created with reckless
|
||
abandon by calling <code>clone</code>.</p>
|
||
<p>When all senders are dropped, the channel is closed and no other sends are
|
||
possible. In a channel with a buffer, receivers continue to consume values
|
||
until the buffer is empty, at which point, a <code>None</code> value is always returned
|
||
immediately.</p>
|
||
<p>No special semantics are enforced when all receivers are dropped. Asynchronous
|
||
sends will continue to work. Synchronous sends will block indefinitely when
|
||
the buffer is full. A send on a rendezvous channel will also block
|
||
indefinitely. (<strong>NOTE</strong>: This could be changed!)</p>
|
||
<p>All channels satisfy <em>both</em> <code>Send</code> and <code>Sync</code> and can be freely mixed in
|
||
<code>chan_select!</code>. Said differently, the synchronization semantics of a channel
|
||
are encoded upon construction, but are otherwise indistinguishable to the
|
||
type system.</p>
|
||
<p>Values sent on channels are subject to the normal restrictions Rust has on
|
||
values crossing thread boundaries. i.e., Values must implement <code>Send</code> and/or
|
||
<code>Sync</code>. (An <code>Rc<T></code> <em>cannot</em> be sent on a channel, but a channel can be sent
|
||
on a channel!)</p>
|
||
<h1 id="example-rendezvous-channel" class="section-header"><a href="#example-rendezvous-channel">Example: rendezvous channel</a></h1>
|
||
<p>A simple example demonstrating a rendezvous channel:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="kw">let</span> (<span class="ident">send</span>, <span class="ident">recv</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> <span class="ident">send</span>.<span class="ident">send</span>(<span class="number">5</span>));
|
||
<span class="macro">assert_eq</span><span class="macro">!</span>(<span class="ident">recv</span>.<span class="ident">recv</span>(), <span class="prelude-val">Some</span>(<span class="number">5</span>)); <span class="comment">// blocks until the previous send occurs</span></pre>
|
||
<h1 id="example-synchronous-channel" class="section-header"><a href="#example-synchronous-channel">Example: synchronous channel</a></h1>
|
||
<p>Similarly, an example demonstrating a synchronous channel:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">let</span> (<span class="ident">send</span>, <span class="ident">recv</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">1</span>);
|
||
<span class="ident">send</span>.<span class="ident">send</span>(<span class="number">5</span>); <span class="comment">// doesn't block because of the buffer</span>
|
||
<span class="macro">assert_eq</span><span class="macro">!</span>(<span class="ident">recv</span>.<span class="ident">recv</span>(), <span class="prelude-val">Some</span>(<span class="number">5</span>));</pre>
|
||
<h1 id="example-multiple-producers-and-multiple-consumers" class="section-header"><a href="#example-multiple-producers-and-multiple-consumers">Example: multiple producers and multiple consumers</a></h1>
|
||
<p>An example demonstrating multiple consumers and multiple producers:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="kw">let</span> <span class="ident">r</span> <span class="op">=</span> {
|
||
<span class="kw">let</span> (<span class="ident">s</span>, <span class="ident">r</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="kw">for</span> <span class="ident">letter</span> <span class="kw">in</span> <span class="macro">vec</span><span class="macro">!</span>[<span class="string">'a'</span>, <span class="string">'b'</span>, <span class="string">'c'</span>, <span class="string">'d'</span>] {
|
||
<span class="kw">let</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">s</span>.<span class="ident">clone</span>();
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> {
|
||
<span class="kw">for</span> _ <span class="kw">in</span> <span class="number">0</span>..<span class="number">10</span> {
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="ident">letter</span>);
|
||
}
|
||
});
|
||
}
|
||
<span class="comment">// This extra lexical scope will drop the initial</span>
|
||
<span class="comment">// sender we created. Thus, the channel will be</span>
|
||
<span class="comment">// closed when all threads spawned above has completed.</span>
|
||
<span class="ident">r</span>
|
||
};
|
||
|
||
<span class="comment">// A wait group lets us synchronize the completion of multiple threads.</span>
|
||
<span class="kw">let</span> <span class="ident">wg</span> <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">WaitGroup</span>::<span class="ident">new</span>();
|
||
<span class="kw">for</span> _ <span class="kw">in</span> <span class="number">0</span>..<span class="number">4</span> {
|
||
<span class="ident">wg</span>.<span class="ident">add</span>(<span class="number">1</span>);
|
||
<span class="kw">let</span> <span class="ident">wg</span> <span class="op">=</span> <span class="ident">wg</span>.<span class="ident">clone</span>();
|
||
<span class="kw">let</span> <span class="ident">r</span> <span class="op">=</span> <span class="ident">r</span>.<span class="ident">clone</span>();
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> {
|
||
<span class="kw">for</span> <span class="ident">letter</span> <span class="kw">in</span> <span class="ident">r</span> {
|
||
<span class="macro">println</span><span class="macro">!</span>(<span class="string">"Received letter: {}"</span>, <span class="ident">letter</span>);
|
||
}
|
||
<span class="ident">wg</span>.<span class="ident">done</span>();
|
||
});
|
||
}
|
||
|
||
<span class="comment">// If this was the end of the process and we didn't call `wg.wait()`, then</span>
|
||
<span class="comment">// the process might quit before all of the consumers were done.</span>
|
||
<span class="comment">// `wg.wait()` will block until all `wg.done()` calls have finished.</span>
|
||
<span class="ident">wg</span>.<span class="ident">wait</span>();</pre>
|
||
<h1 id="example-select-on-multiple-channel-sendsreceives" class="section-header"><a href="#example-select-on-multiple-channel-sendsreceives">Example: Select on multiple channel sends/receives</a></h1>
|
||
<p>An example showing how to use <code>chan_select!</code> to synchronize on sends
|
||
or receives.</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="attribute">#[<span class="ident">macro_use</span>]</span>
|
||
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">chan</span>;
|
||
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="comment">// Emits the fibonacci sequence on the given channel until `quit` receives</span>
|
||
<span class="comment">// a sentinel value.</span>
|
||
<span class="kw">fn</span> <span class="ident">fibonacci</span>(<span class="ident">s</span>: <span class="ident">chan</span>::<span class="ident">Sender</span><span class="op"><</span><span class="ident">u64</span><span class="op">></span>, <span class="ident">quit</span>: <span class="ident">chan</span>::<span class="ident">Receiver</span><span class="op"><</span>()<span class="op">></span>) {
|
||
<span class="kw">let</span> (<span class="kw-2">mut</span> <span class="ident">x</span>, <span class="kw-2">mut</span> <span class="ident">y</span>) <span class="op">=</span> (<span class="number">0</span>, <span class="number">1</span>);
|
||
<span class="kw">loop</span> {
|
||
<span class="comment">// Select will block until at least one of `s.send` or `quit.recv`</span>
|
||
<span class="comment">// is ready to succeed. At which point, it will choose exactly one</span>
|
||
<span class="comment">// send/receive to synchronize.</span>
|
||
<span class="macro">chan_select</span><span class="macro">!</span> {
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="ident">x</span>) <span class="op">=></span> {
|
||
<span class="kw">let</span> <span class="ident">oldx</span> <span class="op">=</span> <span class="ident">x</span>;
|
||
<span class="ident">x</span> <span class="op">=</span> <span class="ident">y</span>;
|
||
<span class="ident">y</span> <span class="op">=</span> <span class="ident">oldx</span> <span class="op">+</span> <span class="ident">y</span>;
|
||
},
|
||
<span class="ident">quit</span>.<span class="ident">recv</span>() <span class="op">=></span> {
|
||
<span class="macro">println</span><span class="macro">!</span>(<span class="string">"quit"</span>);
|
||
<span class="kw">return</span>;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
<span class="kw">fn</span> <span class="ident">main</span>() {
|
||
<span class="kw">let</span> (<span class="ident">s</span>, <span class="ident">r</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="kw">let</span> (<span class="ident">qs</span>, <span class="ident">qr</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="comment">// Spawn a thread and ask for the first 10 numbers in the fibonacci</span>
|
||
<span class="comment">// sequence.</span>
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> {
|
||
<span class="kw">for</span> _ <span class="kw">in</span> <span class="number">0</span>..<span class="number">10</span> {
|
||
<span class="macro">println</span><span class="macro">!</span>(<span class="string">"{}"</span>, <span class="ident">r</span>.<span class="ident">recv</span>().<span class="ident">unwrap</span>());
|
||
}
|
||
<span class="comment">// Dropping all sending channels causes the receive channel to</span>
|
||
<span class="comment">// immediately and always synchronize (because the channel is closed).</span>
|
||
<span class="ident">drop</span>(<span class="ident">qs</span>);
|
||
});
|
||
<span class="ident">fibonacci</span>(<span class="ident">s</span>, <span class="ident">qr</span>);
|
||
}</pre>
|
||
<h1 id="example-non-blocking-sendsreceives" class="section-header"><a href="#example-non-blocking-sendsreceives">Example: non-blocking sends/receives</a></h1>
|
||
<p>This crate specifically does not expose methods like <code>try_send</code> or <code>try_recv</code>.
|
||
Instead, you should prefer using <code>chan_select!</code> to perform a non-blocking
|
||
send or receive. This can be done by telling select what to do when no
|
||
synchronization events are available.</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">let</span> (<span class="ident">s</span>, _) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="macro">chan_select</span><span class="macro">!</span> {
|
||
<span class="ident">default</span> <span class="op">=></span> <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Send failed."</span>),
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="string">"some data"</span>) <span class="op">=></span> <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Send succeeded."</span>),
|
||
}</pre>
|
||
<p>When <code>chan_select!</code> first runs, it will check if <code>s.send(...)</code> can succeed
|
||
<em>without blocking</em>. If so, <code>chan_select!</code> will permit the channels to
|
||
rendezvous. However, if there is no <code>recv</code> call to accept the send, then
|
||
<code>chan_select!</code> will immediately execute the <code>default</code> arm.</p>
|
||
<h1 id="example-the-sentinel-channel-idiom" class="section-header"><a href="#example-the-sentinel-channel-idiom">Example: the sentinel channel idiom</a></h1>
|
||
<p>When writing concurrent programs with <code>chan</code>, you will often find that you need
|
||
to somehow "wait" until some operation is done. For example, let's say you want
|
||
to run a function in a separate thread, but wait until it completes. Here's
|
||
one way to do it:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="kw">fn</span> <span class="ident">do_work</span>(<span class="ident">done</span>: <span class="ident">chan</span>::<span class="ident">Sender</span><span class="op"><</span>()<span class="op">></span>) {
|
||
<span class="comment">// do something</span>
|
||
|
||
<span class="comment">// signal that we're done.</span>
|
||
<span class="ident">done</span>.<span class="ident">send</span>(());
|
||
}
|
||
|
||
<span class="kw">fn</span> <span class="ident">main</span>() {
|
||
<span class="kw">let</span> (<span class="ident">sdone</span>, <span class="ident">rdone</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> <span class="ident">do_work</span>(<span class="ident">sdone</span>));
|
||
<span class="comment">// block until work is done, and then quit the program.</span>
|
||
<span class="ident">rdone</span>.<span class="ident">recv</span>();
|
||
}</pre>
|
||
<p>In effect, we've created a new channel that sends unit values. When we're
|
||
done doing work, we send a unit value and <code>main</code> waits for it to be delivered.</p>
|
||
<p>Another way of achieving the same thing is to simply close the channel. Once
|
||
the channel is closed, any previously blocked receive operations become
|
||
immediately unblocked. What's even cooler is that channels are closed
|
||
automatically when all senders are dropped. So the new program looks something
|
||
like this:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="kw">fn</span> <span class="ident">do_work</span>(<span class="ident">_done</span>: <span class="ident">chan</span>::<span class="ident">Sender</span><span class="op"><</span>()<span class="op">></span>) {
|
||
<span class="comment">// do something</span>
|
||
}
|
||
|
||
<span class="kw">fn</span> <span class="ident">main</span>() {
|
||
<span class="kw">let</span> (<span class="ident">sdone</span>, <span class="ident">rdone</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> <span class="ident">do_work</span>(<span class="ident">sdone</span>));
|
||
<span class="comment">// block until work is done, and then quit the program.</span>
|
||
<span class="ident">rdone</span>.<span class="ident">recv</span>();
|
||
}</pre>
|
||
<p>We no longer need to explicitly do anything with the <code>_done</code> channel. We give
|
||
<code>do_work</code> ownership of the channel, but as soon as the function stops
|
||
executing, <code>_done</code> is dropped, the channel is closed and <code>rdone.recv()</code>
|
||
unblocks.</p>
|
||
<h1 id="example-i-want-more" class="section-header"><a href="#example-i-want-more">Example: I want more!</a></h1>
|
||
<p>There are some examples in this crate's repository:
|
||
https://github.com/BurntSushi/chan/tree/master/examples</p>
|
||
<p>Here is a nice example using the <code>chan-signal</code> crate to read lines from
|
||
stdin while gracefully quitting after receiving a <code>INT</code> or <code>TERM</code>
|
||
signal:
|
||
https://github.com/BurntSushi/chan-signal/blob/master/examples/read_names.rs</p>
|
||
<p>A non-trivial program for periodically sending email with the output of
|
||
running a command: https://github.com/BurntSushi/rust-cmail (The source is
|
||
commented more heavily than normal.)</p>
|
||
<h1 id="when-are-channel-operations-non-blocking" class="section-header"><a href="#when-are-channel-operations-non-blocking">When are channel operations non-blocking?</a></h1>
|
||
<p>Non-blocking in this context means "a send/recv operation can synchronize
|
||
immediately." (Under the hood, a mutex may still be acquired, which could
|
||
block.)</p>
|
||
<p>The following is a list of all cases where a channel operation is considered
|
||
non-blocking:</p>
|
||
<ul>
|
||
<li>A send on a synchronous channel whose buffer is not full.</li>
|
||
<li>A receive on a synchronous channel with a non-empty buffer.</li>
|
||
<li>A send on an asynchronous channel.</li>
|
||
<li>A rendezvous send or recv when a corresponding recv or send operation is
|
||
already blocked, respectively.</li>
|
||
<li>A receive on any closed channel.</li>
|
||
</ul>
|
||
<p>Non-blocking semantics are important because they affect the behavior of
|
||
<code>chan_select!</code>. In particular, a <code>chan_select!</code> with a <code>default</code> arm will
|
||
execute the <code>default</code> case if and only if all other operations are blocked.</p>
|
||
<h1 id="which-channel-type-should-i-use" class="section-header"><a href="#which-channel-type-should-i-use">Which channel type should I use?</a></h1>
|
||
<p><a href="http://www.eros-os.org/pipermail/e-lang/2003-January/008183.html">From Ken Kahn</a>:</p>
|
||
<blockquote>
|
||
<p>About 25 years ago I went to dinner with Carl Hewitt and Robin Milner (of
|
||
CSS and pi calculus fame) and they were arguing about synchronous vs.
|
||
asynchronous communication primitives. Carl used the post office metaphor
|
||
while Robin used the telephone. Both quickly admitted that one can implement
|
||
one in the other.</p>
|
||
</blockquote>
|
||
<p>With three channel types to choose from, it may not always be clear which one
|
||
you should use. In fact, there has been a long debate over which are better.
|
||
Here are some rough guidelines:</p>
|
||
<ul>
|
||
<li>Historically, asynchronous channels have been associated with the actor
|
||
model, which means they're a little out of place in a library inspired by
|
||
communicating sequential processes. Nevertheless, an unconstrained buffer can
|
||
be occasionally useful.</li>
|
||
<li>Synchronous channels are useful because their stricter synchronization
|
||
semantics can make it easier to reason about the flow of your program. In
|
||
particular, with a rendezvous channel, one knows that a <code>send</code> unblocks only
|
||
when a corresponding <code>recv</code> consumes the sent value. This makes it <em>feel</em>
|
||
an awful lot like a function call!</li>
|
||
</ul>
|
||
<h1 id="warning-leaks" class="section-header"><a href="#warning-leaks">Warning: leaks</a></h1>
|
||
<p>Channels can be leaked! In particular, if all receivers have been dropped,
|
||
then any future sends will block. Usually this is indicative of a bug in your
|
||
program.</p>
|
||
<p>For example, consider a "generator" style pattern where a thread produces
|
||
values on a channel and another thread consumes in an iterator.</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">thread</span>;
|
||
|
||
<span class="kw">let</span> (<span class="ident">s</span>, <span class="ident">r</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>(<span class="number">0</span>);
|
||
|
||
<span class="ident">thread</span>::<span class="ident">spawn</span>(<span class="kw">move</span> <span class="op">||</span> {
|
||
<span class="kw">for</span> <span class="ident">val</span> <span class="kw">in</span> <span class="ident">r</span> {
|
||
<span class="kw">if</span> <span class="ident">val</span> <span class="op">>=</span> <span class="number">2</span> {
|
||
<span class="kw">break</span>;
|
||
}
|
||
}
|
||
});
|
||
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="number">1</span>);
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="number">2</span>);
|
||
<span class="comment">// This will deadlock because the loop in the thread</span>
|
||
<span class="comment">// above quits after receiving `2`.</span>
|
||
<span class="ident">s</span>.<span class="ident">send</span>(<span class="number">3</span>);</pre>
|
||
<p>If the iterator loop quits early, the channel's buffer could fill up, which
|
||
will indefinitely block all future send operations.</p>
|
||
<p>(These leaks/deadlocks are detectable in most circumstances, and a <code>send</code>
|
||
operation could be made to wake up and either return an error or panic. The
|
||
semantics here are still experimental.)</p>
|
||
<h1 id="warning-more-leaks" class="section-header"><a href="#warning-more-leaks">Warning: more leaks</a></h1>
|
||
<p>It will always be possible to leak a channel in safe code regardless of the
|
||
channel's semantics. For example:</p>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">mem</span>::<span class="ident">forget</span>;
|
||
|
||
<span class="kw">let</span> (<span class="ident">s</span>, <span class="ident">r</span>) <span class="op">=</span> <span class="ident">chan</span>::<span class="ident">sync</span>::<span class="op"><</span>()<span class="op">></span>(<span class="number">0</span>);
|
||
<span class="ident">forget</span>(<span class="ident">s</span>);
|
||
<span class="comment">// Blocks forever because the channel is never closed.</span>
|
||
<span class="ident">r</span>.<span class="ident">recv</span>();</pre>
|
||
<p>In this case, it is impossible for the channel to close because the internal
|
||
reference count will never reach <code>0</code>.</p>
|
||
<h1 id="warning-performance" class="section-header"><a href="#warning-performance">Warning: performance</a></h1>
|
||
<p>The primary purpose of this crate is to provide a safe, concurrent abstraction.
|
||
Notably, it is <em>not</em> a zero-cost abstraction. It is not even a near-zero-cost
|
||
abstraction. Throughput on a channel is startlingly low (see the benchmarks
|
||
in this crate's repository). Therefore, the channels provided in this crate
|
||
are most useful as a means to structure concurrent programs at a coarse level.</p>
|
||
<p>If your requirements call for performant synchronization of data, <code>chan</code> is not
|
||
the crate you're looking for.</p>
|
||
<h1 id="prior-art" class="section-header"><a href="#prior-art">Prior art</a></h1>
|
||
<p>The semantics encoded in the channels provided by this crate should mirror or
|
||
closely mirror the semantics provided by channels in Go. This includes
|
||
select statements! The major difference between concurrent programs written
|
||
with <code>chan</code> and concurrent programs written with Go is that Go programs can
|
||
benefit from being fast and loose with creating goroutines. In <code>chan</code>, each
|
||
"goroutine" is just an OS thread.</p>
|
||
<p>In terms of writing code:</p>
|
||
<ol>
|
||
<li>Go programs will feature explicit closing of channels. In <code>chan</code>, channels
|
||
are closed <strong>only</strong> when all senders have been dropped.</li>
|
||
<li>Since there is no such thing as a "nil" channel in <code>chan</code>, the semantics Go
|
||
has for nil channels (both sends and receives block indefinitely) do not
|
||
exist in <code>chan</code>.</li>
|
||
<li><code>chan</code> does not expose <code>len</code> or <code>cap</code> methods. (For no reason other than
|
||
to start with a totally minimal API. In particular, calling <code>len</code> or <code>cap</code>
|
||
on a channel is often The Wrong Thing. But not always. So this restriction
|
||
may be lifted in the future.)</li>
|
||
<li>In <code>chan</code>, all channels are either senders or receivers. There is no
|
||
"bidirectional" channel. This is manifest in how channel memory is managed:
|
||
channels are closed when all senders are dropped.</li>
|
||
</ol>
|
||
<p>Of course, Go is not the origin of these ideas, but it has been the
|
||
strongest influence on the design of this library, and at least one of its
|
||
authors has done substantial research on the integration of CSP and programming
|
||
languages.</p>
|
||
</div><h2 id='macros' class='section-header'><a href="#macros">Macros</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="macro" href="macro.chan_select.html"
|
||
title='macro chan::chan_select'>chan_select</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Synchronize on at most one channel send or receive operation.</p>
|
||
|
||
</td>
|
||
</tr></table><h2 id='structs' class='section-header'><a href="#structs">Structs</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.Iter.html"
|
||
title='struct chan::Iter'>Iter</a></td>
|
||
<td class='docblock-short'>
|
||
<p>An iterator over values received in a channel.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.Receiver.html"
|
||
title='struct chan::Receiver'>Receiver</a></td>
|
||
<td class='docblock-short'>
|
||
<p>The receiving half of a channel.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.Sender.html"
|
||
title='struct chan::Sender'>Sender</a></td>
|
||
<td class='docblock-short'>
|
||
<p>The sending half of a channel.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.WaitGroup.html"
|
||
title='struct chan::WaitGroup'>WaitGroup</a></td>
|
||
<td class='docblock-short'>
|
||
<p><code>WaitGroup</code> provides synchronization on the completion of threads.</p>
|
||
|
||
</td>
|
||
</tr></table><h2 id='functions' class='section-header'><a href="#functions">Functions</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.after.html"
|
||
title='fn chan::after'>after</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Creates a new rendezvous channel that is dropped after a timeout.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.after_ms.html"
|
||
title='fn chan::after_ms'>after_ms</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Creates a new rendezvous channel that is dropped after a timeout.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.async.html"
|
||
title='fn chan::async'>async</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Create an asynchronous channel with an unbounded buffer.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.sync.html"
|
||
title='fn chan::sync'>sync</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Create a synchronous channel with a possibly empty buffer.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.tick.html"
|
||
title='fn chan::tick'>tick</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Creates a new rendezvous channel that is "ticked" every duration.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="fn" href="fn.tick_ms.html"
|
||
title='fn chan::tick_ms'>tick_ms</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Creates a new rendezvous channel that is "ticked" every duration.</p>
|
||
|
||
</td>
|
||
</tr></table></section>
|
||
<section id='search' class="content hidden"></section>
|
||
|
||
<section class="footer"></section>
|
||
|
||
<aside id="help" class="hidden">
|
||
<div>
|
||
<h1 class="hidden">Help</h1>
|
||
|
||
<div class="shortcuts">
|
||
<h2>Keyboard Shortcuts</h2>
|
||
|
||
<dl>
|
||
<dt><kbd>?</kbd></dt>
|
||
<dd>Show this help dialog</dd>
|
||
<dt><kbd>S</kbd></dt>
|
||
<dd>Focus the search field</dd>
|
||
<dt><kbd>↑</kbd></dt>
|
||
<dd>Move up in search results</dd>
|
||
<dt><kbd>↓</kbd></dt>
|
||
<dd>Move down in search results</dd>
|
||
<dt><kbd>↹</kbd></dt>
|
||
<dd>Switch tab</dd>
|
||
<dt><kbd>⏎</kbd></dt>
|
||
<dd>Go to active search result</dd>
|
||
<dt><kbd>+</kbd></dt>
|
||
<dd>Expand all sections</dd>
|
||
<dt><kbd>-</kbd></dt>
|
||
<dd>Collapse all sections</dd>
|
||
</dl>
|
||
</div>
|
||
|
||
<div class="infos">
|
||
<h2>Search Tricks</h2>
|
||
|
||
<p>
|
||
Prefix searches with a type followed by a colon (e.g.
|
||
<code>fn:</code>) to restrict the search to a given type.
|
||
</p>
|
||
|
||
<p>
|
||
Accepted types are: <code>fn</code>, <code>mod</code>,
|
||
<code>struct</code>, <code>enum</code>,
|
||
<code>trait</code>, <code>type</code>, <code>macro</code>,
|
||
and <code>const</code>.
|
||
</p>
|
||
|
||
<p>
|
||
Search functions by type signature (e.g.
|
||
<code>vec -> usize</code> or <code>* -> vec</code>)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
|
||
|
||
<script>
|
||
window.rootPath = "../";
|
||
window.currentCrate = "chan";
|
||
</script>
|
||
<script src="../main.js"></script>
|
||
<script defer src="../search-index.js"></script>
|
||
</body>
|
||
</html> |