优化
This commit is contained in:
@@ -1,107 +1,109 @@
|
||||
#include "asio.hpp"
|
||||
#include "Global.h"
|
||||
#include <QApplication>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "Plot_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <algorithm>
|
||||
namespace YSG {
|
||||
struct TimerThreadPrivate {
|
||||
struct RenderSchedulerPrivate {
|
||||
asio::io_context mIoContext;
|
||||
std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> mWorkGuard;
|
||||
std::unique_ptr<asio::thread_pool> mCpuPool;
|
||||
std::thread mSchedulerThread;
|
||||
std::thread::id mSchedulerThreadId;
|
||||
std::atomic_bool mIoActive{false};
|
||||
std::atomic_bool mCpuJoined{false};
|
||||
QList<Plot*> mPlots;
|
||||
std::atomic_bool mRunning{false};
|
||||
std::atomic_bool mCpuJoined{true};
|
||||
};
|
||||
|
||||
TimerThread::TimerThread() : d(std::make_unique<TimerThreadPrivate>()) {
|
||||
connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() {
|
||||
RenderScheduler::RenderScheduler() : d(std::make_unique<RenderSchedulerPrivate>()) {
|
||||
QObject::connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() {
|
||||
shutdown();
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
TimerThread::~TimerThread() = default;
|
||||
|
||||
void TimerThread::run() {
|
||||
d->mSchedulerThreadId = std::this_thread::get_id();
|
||||
RenderScheduler::~RenderScheduler() {
|
||||
shutdown();
|
||||
}
|
||||
void RenderScheduler::start() {
|
||||
if(d->mRunning.exchange(true, std::memory_order_acq_rel)) return;
|
||||
d->mIoContext.restart();
|
||||
d->mWorkGuard = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(d->mIoContext.get_executor());
|
||||
unsigned cpuCount = std::max(1u, std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1u);
|
||||
d->mCpuPool = std::make_unique<asio::thread_pool>(cpuCount);
|
||||
d->mCpuJoined.store(false, std::memory_order_release);
|
||||
d->mIoActive.store(true, std::memory_order_release);
|
||||
for (auto &plot: mPlots) {
|
||||
plot->d->mTimerThread = this;
|
||||
plot->d->mRenderTimer = std::make_unique<asio::steady_timer>(d->mIoContext);
|
||||
plot->d->mRenderSize = QSize(plot->d->mPendingRenderWidth.load(std::memory_order_acquire), plot->d->mPendingRenderHeight.load(std::memory_order_acquire));
|
||||
if(plot->isVisible()) plot->d->mRenderEnabled.store(true, std::memory_order_release);
|
||||
if(plot->d->mRenderEnabled.load(std::memory_order_acquire)) plot->scheduleRenderTimer();
|
||||
plot->requestRender();
|
||||
}
|
||||
d->mIoContext.run();
|
||||
d->mIoActive.store(false, std::memory_order_release);
|
||||
for (auto &plot: mPlots) {
|
||||
if(plot->d->mRenderTimer) {
|
||||
plot->d->mRenderTimer->cancel();
|
||||
plot->d->mRenderTimer.reset();
|
||||
d->mSchedulerThread = std::thread([this]() {
|
||||
d->mSchedulerThreadId = std::this_thread::get_id();
|
||||
for(Plot* plot : d->mPlots) {
|
||||
initializePlotOnScheduler(plot);
|
||||
}
|
||||
}
|
||||
joinCpuPool();
|
||||
d->mCpuPool.reset();
|
||||
d->mWorkGuard.reset();
|
||||
d->mIoContext.run();
|
||||
d->mRunning.store(false, std::memory_order_release);
|
||||
});
|
||||
}
|
||||
void TimerThread::post(std::function<void()> task) {
|
||||
void RenderScheduler::shutdown() {
|
||||
if(!d->mRunning.load(std::memory_order_acquire)) {
|
||||
joinCpuPool();
|
||||
if(d->mSchedulerThread.joinable() && d->mSchedulerThread.get_id() != std::this_thread::get_id()) d->mSchedulerThread.join();
|
||||
d->mCpuPool.reset();
|
||||
d->mWorkGuard.reset();
|
||||
return;
|
||||
}
|
||||
if(isSchedulerThread()) {
|
||||
shutdownOnScheduler();
|
||||
d->mWorkGuard.reset();
|
||||
joinCpuPool();
|
||||
return;
|
||||
}
|
||||
postAndWait([this]() {
|
||||
shutdownOnScheduler();
|
||||
});
|
||||
joinCpuPool();
|
||||
post([this]() {
|
||||
d->mWorkGuard.reset();
|
||||
});
|
||||
if(d->mSchedulerThread.joinable()) d->mSchedulerThread.join();
|
||||
d->mCpuPool.reset();
|
||||
}
|
||||
void RenderScheduler::post(std::function<void()> task) {
|
||||
asio::post(d->mIoContext, std::move(task));
|
||||
}
|
||||
void TimerThread::postCpu(std::function<void()> task) {
|
||||
void RenderScheduler::postCpu(std::function<void()> task) {
|
||||
if(d->mCpuPool) {
|
||||
asio::post(*d->mCpuPool, std::move(task));
|
||||
} else {
|
||||
post(std::move(task));
|
||||
}
|
||||
}
|
||||
bool TimerThread::isSchedulerThread() const {
|
||||
void RenderScheduler::registerPlot(Plot* plot) {
|
||||
if(d->mRunning.load(std::memory_order_acquire) && !isSchedulerThread()) {
|
||||
postAndWait([this, plot]() {
|
||||
registerPlotOnScheduler(plot);
|
||||
});
|
||||
return;
|
||||
}
|
||||
registerPlotOnScheduler(plot);
|
||||
}
|
||||
void RenderScheduler::removePlot(Plot* plot) {
|
||||
if(d->mRunning.load(std::memory_order_acquire) && !isSchedulerThread()) {
|
||||
postAndWait([this, plot]() {
|
||||
removePlotOnScheduler(plot);
|
||||
});
|
||||
return;
|
||||
}
|
||||
removePlotOnScheduler(plot);
|
||||
}
|
||||
bool RenderScheduler::isSchedulerThread() const {
|
||||
return std::this_thread::get_id() == d->mSchedulerThreadId;
|
||||
}
|
||||
asio::io_context& TimerThread::ioContext() {
|
||||
bool RenderScheduler::isRunning() const {
|
||||
return d->mRunning.load(std::memory_order_acquire);
|
||||
}
|
||||
asio::io_context& RenderScheduler::ioContext() {
|
||||
return d->mIoContext;
|
||||
}
|
||||
void TimerThread::removePlot(Plot* plot) {
|
||||
postAndWait([this, plot]() {
|
||||
removePlotOnScheduler(plot);
|
||||
});
|
||||
}
|
||||
void TimerThread::shutdown() {
|
||||
if(!isRunning()) {
|
||||
shutdownOnScheduler();
|
||||
stopSchedulerOnScheduler();
|
||||
joinCpuPool();
|
||||
d->mCpuPool.reset();
|
||||
return;
|
||||
}
|
||||
if(isSchedulerThread()) {
|
||||
shutdownOnScheduler();
|
||||
stopSchedulerOnScheduler();
|
||||
return;
|
||||
}
|
||||
postAndWait([this]() {
|
||||
shutdownOnScheduler();
|
||||
});
|
||||
joinCpuPool();
|
||||
postAndWait([this]() {
|
||||
stopSchedulerOnScheduler();
|
||||
});
|
||||
wait();
|
||||
}
|
||||
void TimerThread::joinCpuPool() {
|
||||
void RenderScheduler::joinCpuPool() {
|
||||
if(d->mCpuPool && !d->mCpuJoined.exchange(true, std::memory_order_acq_rel)) d->mCpuPool->join();
|
||||
}
|
||||
void TimerThread::postAndWait(std::function<void()> task) {
|
||||
if(isSchedulerThread() || !isRunning() || !d->mIoActive.load(std::memory_order_acquire)) {
|
||||
void RenderScheduler::postAndWait(std::function<void()> task) {
|
||||
if(isSchedulerThread() || !d->mRunning.load(std::memory_order_acquire)) {
|
||||
task();
|
||||
return;
|
||||
}
|
||||
@@ -121,18 +123,21 @@ namespace YSG {
|
||||
return done;
|
||||
});
|
||||
}
|
||||
void TimerThread::removePlotOnScheduler(Plot* plot) {
|
||||
mPlots.removeAll(plot);
|
||||
void RenderScheduler::registerPlotOnScheduler(Plot* plot) {
|
||||
if(!d->mPlots.contains(plot)) d->mPlots.append(plot);
|
||||
if(d->mRunning.load(std::memory_order_acquire)) initializePlotOnScheduler(plot);
|
||||
}
|
||||
void RenderScheduler::removePlotOnScheduler(Plot* plot) {
|
||||
d->mPlots.removeAll(plot);
|
||||
PlotPrivate* data = plot->d;
|
||||
data->mRenderEnabled.store(false, std::memory_order_release);
|
||||
if(data->mRenderTimer) {
|
||||
data->mRenderTimer->cancel();
|
||||
data->mRenderTimer.reset();
|
||||
}
|
||||
data->mTimerThread = nullptr;
|
||||
}
|
||||
void TimerThread::shutdownOnScheduler() {
|
||||
for(Plot* plot : mPlots) {
|
||||
void RenderScheduler::shutdownOnScheduler() {
|
||||
for(Plot* plot : d->mPlots) {
|
||||
PlotPrivate* data = plot->d;
|
||||
data->mDestroying.store(true, std::memory_order_release);
|
||||
data->mRenderEnabled.store(false, std::memory_order_release);
|
||||
@@ -140,21 +145,21 @@ namespace YSG {
|
||||
data->mRenderTimer->cancel();
|
||||
data->mRenderTimer.reset();
|
||||
}
|
||||
data->mTimerThread = nullptr;
|
||||
}
|
||||
mPlots.clear();
|
||||
d->mPlots.clear();
|
||||
}
|
||||
void TimerThread::stopSchedulerOnScheduler() {
|
||||
d->mWorkGuard.reset();
|
||||
void RenderScheduler::initializePlotOnScheduler(Plot* plot) {
|
||||
PlotPrivate* data = plot->d;
|
||||
if(!data->mRenderTimer) data->mRenderTimer = std::make_unique<asio::steady_timer>(d->mIoContext);
|
||||
data->mRenderSize = QSize(data->mPendingRenderWidth.load(std::memory_order_acquire), data->mPendingRenderHeight.load(std::memory_order_acquire));
|
||||
if(plot->isVisible()) data->mRenderEnabled.store(true, std::memory_order_release);
|
||||
if(data->mRenderEnabled.load(std::memory_order_acquire)) plot->scheduleRenderTimer();
|
||||
plot->submitRender();
|
||||
}
|
||||
|
||||
void Global::startAllTimeThread() {
|
||||
for (auto &thread: mTimerThreadMap) {
|
||||
if(!thread->isRunning()) thread->start();
|
||||
}
|
||||
RenderScheduler& Global::renderScheduler() {
|
||||
return mRenderScheduler;
|
||||
}
|
||||
|
||||
void Global::timerEvent(QTimerEvent* event) {
|
||||
Q_UNUSED(event)
|
||||
void Global::startRenderScheduler() {
|
||||
mRenderScheduler.start();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user