#include "asio.hpp" #include "Global.h" #include #include #include #include "Plot_p.h" namespace YSG { struct TimerThreadPrivate { asio::io_context mIoContext; std::unique_ptr> mWorkGuard; std::unique_ptr mCpuPool; std::thread::id mSchedulerThreadId; }; TimerThread::TimerThread() : d(std::make_unique()) { connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() { if (isRunning()) { d->mIoContext.stop(); if(d->mCpuPool) d->mCpuPool->stop(); wait(); } delete this; }); } TimerThread::~TimerThread() = default; void TimerThread::run() { d->mSchedulerThreadId = std::this_thread::get_id(); d->mIoContext.restart(); d->mWorkGuard = std::make_unique>(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(cpuCount); for (auto &plot: mPlots) { plot->d->mTimerThread = this; plot->d->mRenderTimer = std::make_unique(d->mIoContext); if(plot->isVisible()) plot->d->mRenderEnabled = true; if(plot->d->mRenderEnabled) plot->scheduleRenderTimer(); plot->requestRender(); } d->mIoContext.run(); for (auto &plot: mPlots) { if(plot->d->mRenderTimer) { plot->d->mRenderTimer->cancel(); plot->d->mRenderTimer.reset(); } } if(d->mCpuPool) { d->mCpuPool->stop(); d->mCpuPool->join(); d->mCpuPool.reset(); } d->mWorkGuard.reset(); } void TimerThread::post(std::function task) { asio::post(d->mIoContext, std::move(task)); } void TimerThread::postCpu(std::function task) { if(d->mCpuPool) { asio::post(*d->mCpuPool, std::move(task)); } else { post(std::move(task)); } } bool TimerThread::isSchedulerThread() const { return std::this_thread::get_id() == d->mSchedulerThreadId; } asio::io_context& TimerThread::ioContext() { return d->mIoContext; } void Global::startAllTimeThread() { for (auto &thread: mTimerThreadMap) { if(!thread->isRunning()) thread->start(); } } void Global::timerEvent(QTimerEvent* event) { Q_UNUSED(event) } }