File: LockFreeQueue.h

package info (click to toggle)
bespokesynth 1.3.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 44,716 kB
  • sloc: cpp: 117,136; ansic: 18,752; python: 593; xml: 74; makefile: 4
file content (89 lines) | stat: -rw-r--r-- 1,908 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
  ==============================================================================

    LockFreeQueue.h
    Created: 1 Apr 2014 6:27:32pm
    Author:  Tom Maisey

  ==============================================================================
*/

#pragma once

/**
 * A simple single producer & consumer lock free queue, based on Herb Sutter's code:
 * http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/
 * 
 * This is a linked list, which can expand arbitrarily without losing old data,
 * but which has poor cache locality (I plan to write a ring buffer version soon).
 */
template <typename T>
class LockFreeQueue
{
public:
   LockFreeQueue()
   {
      first = new Node(T()); // Dummy seperator.

      last.set(first);
      divider.set(first);
   }

   ~LockFreeQueue()
   {
      while (first != nullptr)
      {
         Node* toDel = first;
         first = toDel->next;
         delete toDel;
      }
   }

   /**
     * Add an item to the queue. Obviously, should only be called from producer's thread.
     */
   void produce(const T& t)
   {
      last.get()->next = new Node(t);

      last.set(last.get()->next);

      while (first != divider.get())
      { // trim unused nodes
         Node* tmp = first;
         first = first->next;
         delete tmp;
      }
   }

   /**
     * Consume an item in the queue. Returns false if no items left to consume.
     */
   bool consume(T& result)
   {
      Node* div = divider.get();

      if (div != last.get())
      { // if queue is nonempty
         result = div->next->value; // copy requested value
         divider.set(div->next); // publish that we took it
         return true;
      }

      return false;
   }

private:
   struct Node
   {
      Node(const T& val)
      : value(val)
      {}

      T value;
      Node* next{ nullptr };
   };

   Node* first{ nullptr };
   Atomic<Node*> divider, last;
};