Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>For the fun of it, here is a lock-free implementation:</p> <pre><code>public sealed class MessageWrapper { private int pendingB; public Message WrapA(int a, int millisecondsTimeout) { int b = Interlocked.Exchange(ref pendingB, -1); return new Message(a, b == -1 ? null : b); } public Message WrapB(int b, int millisecondsTimeout) { var sw = new SpinWait(); while (Interlocked.CompareExchange(ref pendingB, b, -1) != -1) { // Spin sw.SpinOnce(); if (sw.NextSpinWillYield) { // Let us make progress instead of yielding the processor // (avoid context switch) return new Message(null, b); } } return null; } } </code></pre> <p><strong>Results</strong></p> <p>Original implementation:</p> <pre><code>00:00:02.0433298 0: 0 A: 733 B: 233 AB: 67 Generated A: 800, Sent A: 800 Generated B: 300, Sent B: 300 </code></pre> <p>Lock-free implementation:</p> <pre><code>00:00:01.2546310 0: 0 A: 717 B: 217 AB: 83 Generated A: 800, Sent A: 800 Generated B: 300, Sent B: 300 </code></pre> <p><strong>Update</strong></p> <p>Unfortunately, above implementation has a bug plus some shortcoming. Here is an improved version:</p> <pre><code>public class MessageWrapper { private int pendingB = EMPTY; private const int EMPTY = -1; public Message WrapA(int a, int millisecondsTimeout) { int? b; int count = 0; while ((b = Interlocked.Exchange(ref pendingB, EMPTY)) == EMPTY) { if (count % 7 == 0) { Thread.Sleep(0); } else if (count % 23 == 0) { Thread.Sleep(1); } else { Thread.Yield(); } if (++count == 480) { return new Message(a, null); } } return new Message(a, b); } public Message WrapB(int b, int millisecondsTimeout) { int count = 0; while (Interlocked.CompareExchange(ref pendingB, b, EMPTY) != EMPTY) { // Spin Thread.SpinWait((4 &lt;&lt; count++)); if (count &gt; 10) { // We didn't manage to place our payload. // Let's send it ourselves: return new Message(null, b); } } // We placed our payload. // Wait some more to see if some WrapA snatches it. while (Interlocked.CompareExchange(ref pendingB, EMPTY, EMPTY) == b) { Thread.SpinWait((4 &lt;&lt; count++)); if (count &gt; 20) { // No WrapA came along. Pity, we will have to send it ourselves int payload = Interlocked.CompareExchange(ref pendingB, EMPTY, b); return payload == b ? new Message(null, b) : null; } } return null; } } </code></pre> <p>Results:</p> <p>OP's implementation</p> <pre><code>00:00:02.1389474 0: 0 A: 722 B: 222 AB: 78 Generated A: 800, Sent A: 800 Generated B: 300, Sent B: 300 </code></pre> <p>Second implementation:</p> <pre><code>00:00:01.2752425 0: 0 A: 700 B: 200 AB: 100 Generated A: 800, Sent A: 800 Generated B: 300, Sent B: 300 </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload