range-lock 0.1.0

Vec range lock
Documentation
<div id="range-lock-multithread-range-lock-for-vec">
<h2>range-lock - Multithread range lock for Vec</h2>
<p><a href="https://bues.ch/" rel="nofollow">https://bues.ch/</a></p>
<p>Provides multi-threaded access to a single Vec&lt;T&gt; instance. Any thread can atomically request access to a slice of the Vec. Such access is granted, if no other thread is simultaneously holding the right to access an overlapping slice.</p>
</div>
<div id="usage">
<h2>Usage</h2>
<p>Add this to your Cargo.toml:</p>
<pre><span class="k">[dependencies]</span>
<span class="n">range-lock</span> <span class="o">=</span> <span class="s">&quot;0.1&quot;</span>
</pre>
<p>Example usage:</p>
<pre><span class="k">extern</span><span class="w"> </span><span class="k">crate</span><span class="w"> </span><span class="n">range_lock</span><span class="p">;</span><span class="w">
</span><span class="k">use</span><span class="w"> </span><span class="n">range_lock</span>::<span class="n">RangeLock</span><span class="p">;</span><span class="w">
</span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="p">{</span><span class="n">Arc</span><span class="p">,</span><span class="w"> </span><span class="n">Barrier</span><span class="p">};</span><span class="w">
</span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">thread</span><span class="p">;</span><span class="w">

</span><span class="c1">// The data that will simultaneously be accessed from the threads.
</span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="mi">13</span><span class="p">];</span><span class="w">

</span><span class="c1">// Embed the data in a RangeLock
// and clone atomic references to it for the threads.
</span><span class="kd">let</span><span class="w"> </span><span class="n">data_lock0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">RangeLock</span>::<span class="n">new</span><span class="p">(</span><span class="n">data</span><span class="p">));</span><span class="w">
</span><span class="kd">let</span><span class="w"> </span><span class="n">data_lock1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data_lock0</span><span class="p">);</span><span class="w">
</span><span class="kd">let</span><span class="w"> </span><span class="n">data_lock2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data_lock0</span><span class="p">);</span><span class="w">

</span><span class="c1">// Thread barrier, only for demonstration purposes.
</span><span class="kd">let</span><span class="w"> </span><span class="n">barrier0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">Barrier</span>::<span class="n">new</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span><span class="w">
</span><span class="kd">let</span><span class="w"> </span><span class="n">barrier1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&amp;</span><span class="n">barrier0</span><span class="p">);</span><span class="w">

</span><span class="c1">// Spawn first thread.
</span><span class="kd">let</span><span class="w"> </span><span class="n">thread0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">guard</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_lock0</span><span class="p">.</span><span class="n">try_lock</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">2</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;T0: Failed to lock 0..2&quot;</span><span class="p">);</span><span class="w">
        </span><span class="n">guard</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">100</span><span class="p">;</span><span class="w"> </span><span class="c1">// Write to data[0]
</span><span class="w">    </span><span class="p">}</span><span class="w">
    </span><span class="n">barrier0</span><span class="p">.</span><span class="n">wait</span><span class="p">();</span><span class="w"> </span><span class="c1">// Synchronize with second thread.
</span><span class="w">    </span><span class="p">{</span><span class="w">
        </span><span class="kd">let</span><span class="w"> </span><span class="n">guard</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_lock0</span><span class="p">.</span><span class="n">try_lock</span><span class="p">(</span><span class="mi">2</span><span class="o">..</span><span class="mi">4</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;T0: Failed to lock 2..4&quot;</span><span class="p">);</span><span class="w">
        </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">guard</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="mi">200</span><span class="p">);</span><span class="w"> </span><span class="c1">// Read from data[2]
</span><span class="w">    </span><span class="p">}</span><span class="w">
</span><span class="p">});</span><span class="w">

</span><span class="c1">// Spawn second thread.
</span><span class="kd">let</span><span class="w"> </span><span class="n">thread1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">guard</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_lock1</span><span class="p">.</span><span class="n">try_lock</span><span class="p">(</span><span class="mi">2</span><span class="o">..</span><span class="mi">4</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;T1: Failed to lock 2..4&quot;</span><span class="p">);</span><span class="w">
        </span><span class="n">guard</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">200</span><span class="p">;</span><span class="w"> </span><span class="c1">// Write to data[2]
</span><span class="w">    </span><span class="p">}</span><span class="w">
    </span><span class="n">barrier1</span><span class="p">.</span><span class="n">wait</span><span class="p">();</span><span class="w"> </span><span class="c1">// Synchronize with first thread.
</span><span class="w">    </span><span class="p">{</span><span class="w">
        </span><span class="kd">let</span><span class="w"> </span><span class="n">guard</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_lock1</span><span class="p">.</span><span class="n">try_lock</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">2</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;T1: Failed to lock 0..2&quot;</span><span class="p">);</span><span class="w">
        </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">guard</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="mi">100</span><span class="p">);</span><span class="w"> </span><span class="c1">// Read from data[0]
</span><span class="w">    </span><span class="p">}</span><span class="w">
</span><span class="p">});</span><span class="w">

</span><span class="c1">// Wait for both threads to finish and check result.
</span><span class="n">thread0</span><span class="p">.</span><span class="n">join</span><span class="p">().</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;Thread 0 failed&quot;</span><span class="p">);</span><span class="w">
</span><span class="n">thread1</span><span class="p">.</span><span class="n">join</span><span class="p">().</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;Thread 1 failed&quot;</span><span class="p">);</span><span class="w">

</span><span class="c1">// Unwrap the data from the lock.
</span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">try_unwrap</span><span class="p">(</span><span class="n">data_lock2</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">&quot;Arc unwrap failed&quot;</span><span class="p">).</span><span class="n">into_inner</span><span class="p">();</span><span class="w">

</span><span class="c1">// Check the data that has been modified by the threads.
</span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">,</span><span class="w"> </span><span class="mi">13</span><span class="p">]);</span>
</pre>
</div>
<div id="todo">
<h2>TODO</h2>
<p>The API of range-lock is currently very simple and only provides the bare minimum.</p>
<p>The following new features might be candidates for future releases:</p>
<ul>
<li>Optimize the range overlap search algorithm.</li>
<li>Sleeping lock, in case of lock contention.</li>
<li>Add support for arrays.</li>
<li>Add support for non-Vec/array iterables?</li>
</ul>
</div>
<div id="license">
<h2>License</h2>
<p>Copyright (c) 2021 Michael Buesch &lt;<a href="mailto:m&#37;&#52;&#48;bues&#46;ch">m<span>&#64;</span>bues<span>&#46;</span>ch</a>&gt;</p>
<p>Licensed under the Apache License version 2.0 or the MIT license, at your option.</p>
</div>