telemetry
Dependents: Everything Sequential_Timing FixedPWM FixedPWMWill
queue.h
- Committer:
- vsutardja
- Date:
- 2016-03-18
- Revision:
- 0:aca5a32d2759
File content as of revision 0:aca5a32d2759:
#include <stddef.h> #include <stdint.h> #ifndef _QUEUE_H_ #define _QUEUE_H_ namespace telemetry { /** * Statically allocated, lock-free queue. * Thread-safe if used in single-producer single-consumer mode. */ template <typename T, size_t N> class Queue { public: Queue() : read_ptr(values), write_ptr(values), begin(values), last(values + N) {} // Return true if the queue is full (enqueue will return false). bool full() const { if (read_ptr == begin) { // Read pointer at beginning, need to wrap around check. if (write_ptr == last) { return true; } else { return false; } } else { if (write_ptr == (read_ptr - 1)) { return true; } else { return false; } } } // Return true if the queue is empty (dequeue will return false). bool empty() const { return (read_ptr == write_ptr); } /** * Puts a new value to the tail of the queue. Returns true if successful, * false if not. */ bool enqueue(const T& value) { if (full()) { return false; } //memcpy((void*)write_ptr, &value, sizeof(T)); // Make it array-compatible. *write_ptr = value; if (write_ptr == last) { write_ptr = begin; } else { write_ptr++; } return true; } /** * Assigns output to the last element in the queue. */ bool dequeue(T* output) { if (empty()) { return false; } //memcpy(output, (void*)read_ptr, sizeof(T)); // Make it array-compatible. *output = *read_ptr; if (read_ptr == last) { read_ptr = begin; } else { read_ptr++; } return true; } protected: // Lots of volatiles to prevent compiler reordering which could corrupt data // when accessed by multiple threads. Yes, it's completely overkill, but // memory fences aren't in earlier C++ versions. volatile T values[N+1]; // Read pointer, points to next element to be returned by dequeue. // Queue is empty if this equals write_ptr. Must never be incremented // past write_ptr. volatile T* volatile read_ptr; // Write pointer, points to next location to be written by enqueue. // Must never be incremented to read_ptr. Queue is full when this is one // less than read_ptr. volatile T* volatile write_ptr; // Pointer to beginning of array, cleaner than using values directly. volatile T* const begin; // Pointer to one past the last element of the array. volatile T* const last; }; } #endif