锁优化
This commit is contained in:
+75
-4
@@ -278,7 +278,7 @@ WaterFallRingBuffer ringBuffer
|
||||
TimeAxis::mRingBuffer
|
||||
SweepFrequent::mFrequents
|
||||
Planisphere::dataList
|
||||
Afterglow cachedPowerData / oldCachePowerData / mutexPowerData
|
||||
Afterglow cachedPowerData / oldCachePowerData / mergedPowerData
|
||||
Spectrum curPowers / maxPowers / minPowers / frequents
|
||||
```
|
||||
|
||||
@@ -385,13 +385,11 @@ Input dirty 不递增 edit_state.version。
|
||||
prepareData 的标准流程:
|
||||
|
||||
```text
|
||||
lock mBufferLock
|
||||
syncStatePipeline()
|
||||
读取 render_state 配置
|
||||
读取 render_input 增量
|
||||
更新 RenderCache
|
||||
clearRenderInput()
|
||||
unlock mBufferLock
|
||||
```
|
||||
|
||||
syncStatePipeline 内部同时处理:
|
||||
@@ -401,6 +399,14 @@ State edit -> ready -> render
|
||||
Input edit -> ready -> render
|
||||
```
|
||||
|
||||
prepareData 不再持有 RenderData 对象级锁。
|
||||
|
||||
edit_state 写入必须通过 State_Edit lease。
|
||||
|
||||
edit_input 写入必须通过 Input_Edit lease。
|
||||
|
||||
RenderCache 只允许 render 流程内部更新。
|
||||
|
||||
prepareData 不应该写 Color。
|
||||
|
||||
prepareData 不应该触发 QWidget 绘制。
|
||||
@@ -453,7 +459,72 @@ draw 不做输入队列交换。
|
||||
把配置项放 InputData。
|
||||
```
|
||||
|
||||
## 12. 最终规则
|
||||
## 12. 锁使用边界
|
||||
|
||||
radio 渲染链路不允许使用 RenderData 对象级大锁。
|
||||
|
||||
允许存在的同步只有下面几类:
|
||||
|
||||
```text
|
||||
Triple_Role_Buffer_Control:
|
||||
使用 atomic busy / slot_state / wait / notify。
|
||||
只保护物理 buffer lease 和 role 交换。
|
||||
|
||||
RenderPipeline:
|
||||
使用 color buffer version / paintRequestPending / editStateVersion。
|
||||
只保护帧发布和 Qt update 请求合并。
|
||||
|
||||
Plot / TimerThread:
|
||||
mRenderEnabled / mDestroying / mActiveRenderTasks / pending render size 使用 atomic。
|
||||
mRenderTaskMutex + mRenderTaskDone 只用于 Plot 析构等待已投递任务结束。
|
||||
TimerThread::postAndWait 的局部 mutex + condition_variable 只用于跨线程同步 shutdown/removePlot。
|
||||
|
||||
PerformanceShower:
|
||||
mMutex 只保护统计 map 和显示列表。
|
||||
```
|
||||
|
||||
不允许重新引入:
|
||||
|
||||
```text
|
||||
RenderData::mBufferLock
|
||||
prepareData 全局锁
|
||||
render size mutex
|
||||
Graphic resize mutex
|
||||
HoverInfo 独立 mutex
|
||||
PrePareMutiDataMutex
|
||||
SpinLock / SpinLockGuard
|
||||
Singleton mutex + atomic 双重检查
|
||||
```
|
||||
|
||||
prepareData 和 draw 的并发边界由调度流保证:
|
||||
|
||||
```text
|
||||
submitRender 进入 asio scheduler。
|
||||
scheduler 串行推进 jobState。
|
||||
prepareData 在 scheduler 阶段消费 State/Input。
|
||||
renderColor 在 CPU 阶段只读取 State_Render 和 RenderCache。
|
||||
finishRender 回到 scheduler 发布 Color。
|
||||
```
|
||||
|
||||
CPP_Core 和第三方库内部同步不属于 radio 渲染架构边界:
|
||||
|
||||
```text
|
||||
RingBuffer_MT / StreamRingBuffer_MT:
|
||||
通用多线程容器版本。
|
||||
|
||||
SM_RingBuffer / Cross_Process_Mutex:
|
||||
跨进程共享内存同步。
|
||||
|
||||
Frequency_Limit:
|
||||
通用频率限制器。
|
||||
|
||||
spdlog / asio / googlepinyin:
|
||||
第三方或通用库内部同步。
|
||||
```
|
||||
|
||||
这些同步不能向 RenderData、prepareData、draw 路径扩散。
|
||||
|
||||
## 13. 最终规则
|
||||
|
||||
```text
|
||||
State 负责配置快照。
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define BackEnd_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
||||
@@ -14,62 +14,7 @@
|
||||
#include <QtWidgets>
|
||||
#include <QtWidgetsDepends>
|
||||
#include <functional>
|
||||
|
||||
#include "psc_global_include/Singleton.hpp"
|
||||
|
||||
// template <typename Derived>
|
||||
// class Singleton {
|
||||
// public:
|
||||
// static Derived* instance() {
|
||||
// Derived* temp = instance_.load(std::memory_order_acquire);
|
||||
// if (temp == nullptr) {
|
||||
// std::lock_guard<std::mutex> lock(mutex_);
|
||||
// temp = instance_.load(std::memory_order_relaxed);
|
||||
// if (temp == nullptr) {
|
||||
// temp = new Derived;
|
||||
// instance_.store(temp, std::memory_order_release);
|
||||
// }
|
||||
// }
|
||||
// return temp;
|
||||
// }
|
||||
// Singleton(const Singleton&) = delete;
|
||||
// Singleton& operator=(const Singleton&) = delete;
|
||||
// protected:
|
||||
// Singleton() = default;
|
||||
// ~Singleton() = default;
|
||||
// private:
|
||||
// static std::atomic<Derived*> instance_;
|
||||
// static std::mutex mutex_;
|
||||
// };
|
||||
// template<typename Derived>
|
||||
// std::atomic<Derived*> Singleton<Derived>::instance_(nullptr);
|
||||
// template<typename Derived>
|
||||
// std::mutex Singleton<Derived>::mutex_;
|
||||
|
||||
//template<typename T>
|
||||
//class Singleton {
|
||||
//public:
|
||||
// static T *instance() {
|
||||
// if(!mInstance) {
|
||||
// mInstance = new T();
|
||||
// }
|
||||
// return mInstance;
|
||||
// }
|
||||
// virtual ~Singleton() = default;
|
||||
// Singleton(T &&) = delete;
|
||||
// Singleton(const T &) = delete;
|
||||
// void operator=(const T &) = delete;
|
||||
//protected:
|
||||
// Singleton() = default;
|
||||
// static T* mInstance;
|
||||
//};
|
||||
//template<typename T> T* Singleton<T>::mInstance = nullptr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Global : public Psc::Singleton<Global> {
|
||||
public:
|
||||
explicit Global();
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
#ifndef Toolbox_Singleton_H
|
||||
#define Toolbox_Singleton_H
|
||||
#include <mutex>
|
||||
namespace Toolbox {
|
||||
template<typename Derived>
|
||||
class Singleton {
|
||||
public:
|
||||
static Derived *instance() {
|
||||
Derived *temp = instance_.load(std::memory_order_acquire);
|
||||
if (temp == nullptr) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
temp = instance_.load(std::memory_order_relaxed);
|
||||
if (temp == nullptr) {
|
||||
temp = new Derived;
|
||||
instance_.store(temp, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
static Derived instance;
|
||||
return &instance;
|
||||
}
|
||||
Singleton(const Singleton &) = delete;
|
||||
Singleton &operator=(const Singleton &) = delete;
|
||||
protected:
|
||||
Singleton() = default;
|
||||
~Singleton() = default;
|
||||
private:
|
||||
static std::atomic<Derived *> instance_;
|
||||
static std::mutex mutex_;
|
||||
};
|
||||
template<typename Derived>
|
||||
std::atomic<Derived *> Singleton<Derived>::instance_(nullptr);
|
||||
template<typename Derived>
|
||||
std::mutex Singleton<Derived>::mutex_;
|
||||
}
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
#include <chrono>
|
||||
#include "SpinLock.h"
|
||||
namespace Toolbox {
|
||||
void SpinLock::lock() {
|
||||
while (flag.test_and_set(std::memory_order_acquire)) {}
|
||||
}
|
||||
bool SpinLock::tryLock() {
|
||||
return !flag.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
bool SpinLock::tryLock(int durationMillis) {
|
||||
if (durationMillis == 0) {
|
||||
return tryLock();
|
||||
}
|
||||
auto duration = std::chrono::milliseconds(durationMillis);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (std::chrono::steady_clock::now() - start < duration) {
|
||||
if (tryLock()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void SpinLock::unlock() {
|
||||
flag.clear(std::memory_order_release);
|
||||
}
|
||||
SpinLockGuard::~SpinLockGuard() {
|
||||
if (mLock) mLock->unlock();
|
||||
}
|
||||
SpinLockGuard::SpinLockGuard(SpinLock *lock) : mLock(lock) {
|
||||
if (mLock) mLock->lock();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef Toolbox_SpinLock_H
|
||||
#define Toolbox_SpinLock_H
|
||||
#include <atomic>
|
||||
namespace Toolbox {
|
||||
class SpinLock {
|
||||
public:
|
||||
void lock();
|
||||
bool tryLock();
|
||||
bool tryLock(int durationMillis);
|
||||
void unlock();
|
||||
private:
|
||||
std::atomic_flag flag = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
class SpinLockGuard {
|
||||
public:
|
||||
explicit SpinLockGuard(SpinLock *lock);
|
||||
~SpinLockGuard();
|
||||
private:
|
||||
SpinLock *mLock;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "Node.hpp"
|
||||
#include "CircularLinkedList.hpp"
|
||||
#include "SpinLock.h"
|
||||
#include "Singleton.hpp"
|
||||
#include "RollObject.h"
|
||||
#include "SingletonWidget.hpp"
|
||||
|
||||
Reference in New Issue
Block a user