From 081b6268557924696d7fc3a7dd965a3e92096b9a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 20 Jun 2023 20:12:57 -0500 Subject: [PATCH] Fix crash when switching radar sites while loading data from the old site - Use thread pools owned by radar product manager, unless called statically (#51) --- .../scwx/qt/manager/radar_product_manager.cpp | 129 +++++++++++------- 1 file changed, 78 insertions(+), 51 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp index 9c5e3991..29bbc724 100644 --- a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp @@ -19,7 +19,9 @@ # pragma warning(push, 0) #endif +#include #include +#include #include #include #include @@ -91,7 +93,7 @@ public: group_ {group}, product_ {product}, refreshEnabled_ {false}, - refreshTimer_ {scwx::util::io_context()}, + refreshTimer_ {threadPool_}, refreshTimerMutex_ {}, provider_ {nullptr} { @@ -106,6 +108,8 @@ public: void Disable(); + boost::asio::thread_pool threadPool_ {1u}; + const std::string radarId_; const common::RadarProductGroup group_; const std::string product_; @@ -179,6 +183,8 @@ public: RadarProductManager* self_; + boost::asio::thread_pool threadPool_ {4u}; + std::shared_ptr GetLevel3ProviderManager(const std::string& product); @@ -199,6 +205,10 @@ public: void UpdateRecentRecords(RadarProductRecordList& recentList, std::shared_ptr record); + void LoadNexradFileAsync(CreateNexradFileFunction load, + std::shared_ptr request, + std::mutex& mutex, + std::chrono::system_clock::time_point time); void LoadProviderData(std::chrono::system_clock::time_point time, std::shared_ptr providerManager, RadarProductRecordMap& recordMap, @@ -523,7 +533,8 @@ void RadarProductManager::EnableRefresh(common::RadarProductGroup group, p->GetLevel3ProviderManager(product); // Only enable refresh on available products - scwx::util::async( + boost::asio::post( + p->threadPool_, [=, this]() { providerManager->provider_->RequestAvailableProducts(); @@ -614,7 +625,8 @@ void RadarProductManagerImpl::RefreshData( providerManager->refreshTimer_.cancel(); } - scwx::util::async( + boost::asio::post( + threadPool_, [=, this]() { auto [newObjects, totalObjects] = @@ -774,9 +786,8 @@ void RadarProductManagerImpl::LoadProviderData( providerManager->name(), scwx::util::TimeString(time)); - RadarProductManagerImpl::LoadNexradFile( - [=, &recordMap, &recordMutex, &loadDataMutex]() - -> std::shared_ptr + LoadNexradFileAsync( + [=, &recordMap, &recordMutex]() -> std::shared_ptr { std::shared_ptr existingRecord = nullptr; std::shared_ptr nexradFile = nullptr; @@ -874,11 +885,15 @@ void RadarProductManager::LoadData( { logger_->debug("LoadData()"); - RadarProductManagerImpl::LoadNexradFile( - [=, &is]() -> std::shared_ptr - { return wsr88d::NexradFileFactory::Create(is); }, - request, - fileLoadMutex_); + scwx::util::async( + [=, &is]() + { + RadarProductManagerImpl::LoadNexradFile( + [=, &is]() -> std::shared_ptr + { return wsr88d::NexradFileFactory::Create(is); }, + request, + fileLoadMutex_); + }); } void RadarProductManager::LoadFile( @@ -915,11 +930,15 @@ void RadarProductManager::LoadFile( } }); - RadarProductManagerImpl::LoadNexradFile( - [=]() -> std::shared_ptr - { return wsr88d::NexradFileFactory::Create(filename); }, - request, - fileLoadMutex_); + scwx::util::async( + [=]() + { + RadarProductManagerImpl::LoadNexradFile( + [=]() -> std::shared_ptr + { return wsr88d::NexradFileFactory::Create(filename); }, + request, + fileLoadMutex_); + }); } else if (request != nullptr) { @@ -928,51 +947,58 @@ void RadarProductManager::LoadFile( } } +void RadarProductManagerImpl::LoadNexradFileAsync( + CreateNexradFileFunction load, + std::shared_ptr request, + std::mutex& mutex, + std::chrono::system_clock::time_point time) +{ + boost::asio::post(threadPool_, + [=, &mutex]() + { LoadNexradFile(load, request, mutex, time); }); +} + void RadarProductManagerImpl::LoadNexradFile( CreateNexradFileFunction load, std::shared_ptr request, std::mutex& mutex, std::chrono::system_clock::time_point time) { - scwx::util::async( - [=, &mutex]() + std::unique_lock lock {mutex}; + + std::shared_ptr nexradFile = load(); + + std::shared_ptr record = nullptr; + + bool fileValid = (nexradFile != nullptr); + + if (fileValid) + { + record = types::RadarProductRecord::Create(nexradFile); + + // If the time is already determined, override the time in the file. + // Sometimes, level 2 data has been seen to be a few seconds off + // between filename and file data. Overriding this can help prevent + // issues with locating and storing the correct records. + if (time != std::chrono::system_clock::time_point {}) { - std::unique_lock lock {mutex}; + record->set_time(time); + } - std::shared_ptr nexradFile = load(); + std::shared_ptr manager = + RadarProductManager::Instance(record->radar_id()); - std::shared_ptr record = nullptr; + manager->Initialize(); + record = manager->p->StoreRadarProductRecord(record); + } - bool fileValid = (nexradFile != nullptr); + lock.unlock(); - if (fileValid) - { - record = types::RadarProductRecord::Create(nexradFile); - - // If the time is already determined, override the time in the file. - // Sometimes, level 2 data has been seen to be a few seconds off - // between filename and file data. Overriding this can help prevent - // issues with locating and storing the correct records. - if (time != std::chrono::system_clock::time_point {}) - { - record->set_time(time); - } - - std::shared_ptr manager = - RadarProductManager::Instance(record->radar_id()); - - manager->Initialize(); - record = manager->p->StoreRadarProductRecord(record); - } - - lock.unlock(); - - if (request != nullptr) - { - request->set_radar_product_record(record); - Q_EMIT request->RequestComplete(request); - } - }); + if (request != nullptr) + { + request->set_radar_product_record(record); + Q_EMIT request->RequestComplete(request); + } } void RadarProductManagerImpl::PopulateLevel2ProductTimes( @@ -1349,7 +1375,8 @@ void RadarProductManager::UpdateAvailableProducts() logger_->debug("UpdateAvailableProducts()"); - scwx::util::async( + boost::asio::post( + p->threadPool_, [this]() { auto level3ProviderManager =