More Spin locks experiments

This commit is contained in:
vsonnier 2019-03-05 06:44:58 +01:00
parent fd30710d14
commit 1d2e35cbac
4 changed files with 21 additions and 19 deletions

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
// A non-recursive Mutex implemented as a spin-lock. // A non-recursive Mutex implemented as a spin-lock, implementing the Lockable requirement
class SpinMutex { class SpinMutex {
public: public:
@ -18,6 +18,8 @@ public:
void lock() { while (lock_state.test_and_set(std::memory_order_acquire)); } void lock() { while (lock_state.test_and_set(std::memory_order_acquire)); }
bool try_lock() {return !lock_state.test_and_set(std::memory_order_acquire); }
void unlock() { lock_state.clear(std::memory_order_release); } void unlock() { lock_state.clear(std::memory_order_release); }
private: private:

View File

@ -11,6 +11,7 @@
#include <condition_variable> #include <condition_variable>
#include <typeinfo> #include <typeinfo>
#include <iostream> #include <iostream>
#include "SpinMutex.h"
#define MIN_ITEM_NB (1) #define MIN_ITEM_NB (1)
@ -50,7 +51,7 @@ public:
/*! Destroy safe queue. */ /*! Destroy safe queue. */
~ThreadBlockingQueue() { ~ThreadBlockingQueue() {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
} }
/** /**
@ -59,7 +60,7 @@ public:
* \param[in] nb max of items * \param[in] nb max of items
*/ */
void set_max_num_items(unsigned int max_num_items) { void set_max_num_items(unsigned int max_num_items) {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
if (max_num_items > m_max_num_items) { if (max_num_items > m_max_num_items) {
//Only raise the existing max size, never reduce it //Only raise the existing max size, never reduce it
@ -79,7 +80,7 @@ public:
* \return true if an item was pushed into the queue, else a timeout has occured. * \return true if an item was pushed into the queue, else a timeout has occured.
*/ */
bool push(const value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT,const char* errorMessage = nullptr) { bool push(const value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT,const char* errorMessage = nullptr) {
std::unique_lock < std::mutex > lock(m_mutex); std::unique_lock < SpinMutex > lock(m_mutex);
if (timeout == BLOCKING_INFINITE_TIMEOUT) { if (timeout == BLOCKING_INFINITE_TIMEOUT) {
m_cond_not_full.wait(lock, [this]() // Lambda funct m_cond_not_full.wait(lock, [this]() // Lambda funct
@ -113,7 +114,7 @@ public:
* \param[in] item An item. * \param[in] item An item.
*/ */
bool try_push(const value_type& item) { bool try_push(const value_type& item) {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
if (m_queue.size() >= m_max_num_items) { if (m_queue.size() >= m_max_num_items) {
return false; return false;
@ -131,7 +132,7 @@ public:
* \return true if get an item from the queue, false if no item is received before the timeout. * \return true if get an item from the queue, false if no item is received before the timeout.
*/ */
bool pop(value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = nullptr) { bool pop(value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = nullptr) {
std::unique_lock < std::mutex > lock(m_mutex); std::unique_lock < SpinMutex > lock(m_mutex);
if (timeout == BLOCKING_INFINITE_TIMEOUT) { if (timeout == BLOCKING_INFINITE_TIMEOUT) {
m_cond_not_empty.wait(lock, [this]() // Lambda funct m_cond_not_empty.wait(lock, [this]() // Lambda funct
@ -166,7 +167,7 @@ public:
* \return False is returned if no item is available. * \return False is returned if no item is available.
*/ */
bool try_pop(value_type& item) { bool try_pop(value_type& item) {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
if (m_queue.empty()) { if (m_queue.empty()) {
return false; return false;
@ -184,7 +185,7 @@ public:
* \return Number of items in the queue. * \return Number of items in the queue.
*/ */
size_type size() const { size_type size() const {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
return m_queue.size(); return m_queue.size();
} }
@ -193,7 +194,7 @@ public:
* \return true if queue is empty. * \return true if queue is empty.
*/ */
bool empty() const { bool empty() const {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
return m_queue.empty(); return m_queue.empty();
} }
@ -202,7 +203,7 @@ public:
* \return true if queue is full. * \return true if queue is full.
*/ */
bool full() const { bool full() const {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
return (m_queue.size() >= m_max_num_items); return (m_queue.size() >= m_max_num_items);
} }
@ -210,7 +211,7 @@ public:
* Remove any items in the queue. * Remove any items in the queue.
*/ */
void flush() { void flush() {
std::lock_guard < std::mutex > lock(m_mutex); std::lock_guard < SpinMutex > lock(m_mutex);
m_queue.clear(); m_queue.clear();
m_cond_not_full.notify_all(); m_cond_not_full.notify_all();
} }
@ -221,8 +222,8 @@ private:
std::deque<T> m_queue; std::deque<T> m_queue;
mutable std::mutex m_mutex; mutable SpinMutex m_mutex;
std::condition_variable m_cond_not_empty; std::condition_variable_any m_cond_not_empty;
std::condition_variable m_cond_not_full; std::condition_variable_any m_cond_not_full;
size_t m_max_num_items = MIN_ITEM_NB; size_t m_max_num_items = MIN_ITEM_NB;
}; };

View File

@ -88,7 +88,7 @@ void WaterfallCanvas::attachSpectrumCanvas(SpectrumCanvas *canvas_in) {
} }
void WaterfallCanvas::processInputQueue() { void WaterfallCanvas::processInputQueue() {
std::lock_guard < SpinMutex > lock(tex_update); std::lock_guard < std::mutex > lock(tex_update);
gTimer.update(); gTimer.update();
@ -127,7 +127,7 @@ void WaterfallCanvas::processInputQueue() {
} }
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
std::lock_guard < SpinMutex > lock(tex_update); std::lock_guard < std::mutex > lock(tex_update);
wxPaintDC dc(this); wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
@ -913,7 +913,7 @@ void WaterfallCanvas::updateCenterFrequency(long long freq) {
} }
void WaterfallCanvas::setLinesPerSecond(int lps) { void WaterfallCanvas::setLinesPerSecond(int lps) {
std::lock_guard < SpinMutex > lock(tex_update); std::lock_guard < std::mutex > lock(tex_update);
linesPerSecond = lps; linesPerSecond = lps;

View File

@ -14,7 +14,6 @@
#include "SpectrumCanvas.h" #include "SpectrumCanvas.h"
#include "WaterfallPanel.h" #include "WaterfallPanel.h"
#include "Timer.h" #include "Timer.h"
#include "SpinMutex.h"
class WaterfallCanvas: public InteractiveCanvas { class WaterfallCanvas: public InteractiveCanvas {
public: public:
@ -94,7 +93,7 @@ private:
Timer gTimer; Timer gTimer;
double lpsIndex; double lpsIndex;
bool preBuf; bool preBuf;
SpinMutex tex_update; std::mutex tex_update;
int minBandwidth; int minBandwidth;
std::atomic_bool fft_size_changed; std::atomic_bool fft_size_changed;
// event table // event table