Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>If you're on Windows, you won't be able to use futexes, but Windows Vista has a similar mechanism called <a href="http://locklessinc.com/articles/keyed_events/" rel="noreferrer">Keyed Events</a>. Unfortunately, this isn't part of the published API (it's an NTDLL native API), but you can use it as long as you accept the caveat that it might change in future versions of Windows (and you don't need to run on pre-Vista kernels). Be sure to read the article I linked above. Here's an <strong>untested</strong> sketch of how it might work:</p> <pre><code>/* Interlocked SList queue using keyed event signaling */ struct queue { SLIST_HEADER slist; // Note: Multiple queues can (and should) share a keyed event handle HANDLE keyed_event; // Initial value: 0 // Prior to blocking, the queue_pop function increments this to 1, then // rechecks the queue. If it finds an item, it attempts to compxchg back to // 0; if this fails, then it's racing with a push, and has to block LONG block_flag; }; void init_queue(queue *qPtr) { NtCreateKeyedEvent(&amp;qPtr-&gt;keyed_event, -1, NULL, 0); InitializeSListHead(&amp;qPtr-&gt;slist); qPtr-&gt;blocking = 0; } void queue_push(queue *qPtr, SLIST_ENTRY *entry) { InterlockedPushEntrySList(&amp;qPtr-&gt;slist, entry); // Transition block flag 1 -&gt; 0. If this succeeds (block flag was 1), we // have committed to a keyed-event handshake LONG oldv = InterlockedCompareExchange(&amp;qPtr-&gt;block_flag, 0, 1); if (oldv) { NtReleaseKeyedEvent(qPtr-&gt;keyed_event, (PVOID)qPtr, FALSE, NULL); } } SLIST_ENTRY *queue_pop(queue *qPtr) { SLIST_ENTRY *entry = InterlockedPopEntrySList(&amp;qPtr-&gt;slist); if (entry) return entry; // fast path // Transition block flag 0 -&gt; 1. We must recheck the queue after this point // in case we race with queue_push; however since ReleaseKeyedEvent // blocks until it is matched up with a wait, we must perform the wait if // queue_push sees us LONG oldv = InterlockedCompareExchange(&amp;qPtr-&gt;block_flag, 1, 0); assert(oldv == 0); entry = InterlockedPopEntrySList(&amp;qPtr-&gt;slist); if (entry) { // Try to abort oldv = InterlockedCompareExchange(&amp;qPtr-&gt;block_flag, 0, 1); if (oldv == 1) return entry; // nobody saw us, we can just exit with the value } // Either we don't have an entry, or we are forced to wait because // queue_push saw our block flag. So do the wait NtWaitForKeyedEvent(qPtr-&gt;keyed_event, (PVOID)qPtr, FALSE, NULL); // block_flag has been reset by queue_push if (!entry) entry = InterlockedPopEntrySList(&amp;qPtr-&gt;slist); assert(entry); return entry; } </code></pre> <p>You could also use a similar protocol using <a href="http://msdn.microsoft.com/en-us/library/aa904937%28v=VS.85%29.aspx" rel="noreferrer">Slim Read Write</a> locks and <a href="http://msdn.microsoft.com/en-us/library/ms682052%28v=VS.85%29.aspx" rel="noreferrer">Condition Variables</a>, with a lockless fast path. These are wrappers over keyed events, so they may incur more overhead than using keyed events directly.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

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