From a76dabb12734154177a78033324b40365e7c6f21 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 21 Jul 2021 14:46:48 +0200 Subject: Fix freeze on search reset in manga combined plugin. Fix multithreading issues in AsyncTask --- include/AsyncTask.hpp | 31 +++++++++++++++++++++++++++---- plugins/MangaCombined.hpp | 1 + plugins/Page.hpp | 1 + src/Downloader.cpp | 4 +--- src/QuickMedia.cpp | 11 +++-------- src/plugins/MangaCombined.cpp | 18 ++++++++++++++++-- src/plugins/Youtube.cpp | 3 +++ 7 files changed, 52 insertions(+), 17 deletions(-) diff --git a/include/AsyncTask.hpp b/include/AsyncTask.hpp index 6148923..45b3397 100644 --- a/include/AsyncTask.hpp +++ b/include/AsyncTask.hpp @@ -3,6 +3,7 @@ #include "Program.hpp" #include #include +#include namespace QuickMedia { template @@ -13,6 +14,7 @@ namespace QuickMedia { AsyncTask() = default; AsyncTask(CallbackFunc callback_func, Args&&... args) { + std::lock_guard lock(mutex); std::promise promise; future = promise.get_future(); thread = std::thread(&AsyncTask::thread_handler, this, std::move(promise), std::move(callback_func), std::forward(args)...); @@ -20,12 +22,14 @@ namespace QuickMedia { AsyncTask(AsyncTask &&other) { cancel(); + std::lock_guard lock(mutex); thread = std::move(other.thread); future = std::move(other.future); } AsyncTask& operator=(AsyncTask &&other) { cancel(); + std::lock_guard lock(mutex); thread = std::move(other.thread); future = std::move(other.future); return *this; @@ -36,22 +40,40 @@ namespace QuickMedia { } bool valid() { + std::lock_guard lock(mutex); return future.valid(); } bool ready() { + std::lock_guard lock(mutex); return future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } T get() { - thread.join(); - return future.get(); + std::lock_guard lock(mutex); + if constexpr(std::is_same::value) { + if(thread.joinable()) { + thread.join(); + future.get(); + } + } else { + T result; + if(thread.joinable()) { + thread.join(); + result = std::move(future.get()); + } + return result; + } } void cancel() { - if(valid()) { + std::lock_guard lock(mutex); + if(future.valid()) { program_kill_in_thread(thread.get_id()); - get(); + if(thread.joinable()) { + thread.join(); + future.get(); + } } } private: @@ -66,5 +88,6 @@ namespace QuickMedia { private: std::thread thread; std::future future; + std::mutex mutex; }; } \ No newline at end of file diff --git a/plugins/MangaCombined.hpp b/plugins/MangaCombined.hpp index 5dc4850..dafc884 100644 --- a/plugins/MangaCombined.hpp +++ b/plugins/MangaCombined.hpp @@ -23,6 +23,7 @@ namespace QuickMedia { PluginResult get_page(const std::string &str, int page, BodyItems &result_items) override; PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override; sf::Vector2i get_thumbnail_max_size() override { return sf::Vector2i(101, 141); }; + void cancel_operation() override; private: std::vector search_pages; std::vector search_threads; // TODO: Use async task pool diff --git a/plugins/Page.hpp b/plugins/Page.hpp index 35e778b..07d4e0d 100644 --- a/plugins/Page.hpp +++ b/plugins/Page.hpp @@ -57,6 +57,7 @@ namespace QuickMedia { // This is called both when first navigating to page and when going back to page virtual void on_navigate_to_page(Body *body) { (void)body; } + virtual void cancel_operation() {} std::unique_ptr create_body(bool plain_text_list = false, bool prefer_card_view = false); std::unique_ptr create_search_bar(const std::string &placeholder_text, int search_delay); diff --git a/src/Downloader.cpp b/src/Downloader.cpp index ffb8675..ae84973 100644 --- a/src/Downloader.cpp +++ b/src/Downloader.cpp @@ -384,9 +384,7 @@ namespace QuickMedia { if(youtube_audio_media_proxy) youtube_audio_media_proxy->stop(); - if(downloader_task.valid()) - downloader_task.cancel(); - + downloader_task.cancel(); youtube_video_media_proxy.reset(); youtube_audio_media_proxy.reset(); diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 723e8ec..161ea1a 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -2133,6 +2133,7 @@ namespace QuickMedia { } if(associated_data.search_text_updated && associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && associated_data.fetch_future.valid()) { + tabs[i].page->cancel_operation(); associated_data.fetch_future.cancel(); associated_data.fetch_status = FetchStatus::NONE; } @@ -2580,8 +2581,6 @@ namespace QuickMedia { std::string audio_url; bool has_embedded_audio = true; - - std::string prev_start_time; std::vector media_chapters; @@ -2693,9 +2692,7 @@ namespace QuickMedia { if(youtube_audio_media_proxy) youtube_audio_media_proxy->stop(); - if(youtube_downloader_task.valid()) - youtube_downloader_task.cancel(); - + youtube_downloader_task.cancel(); youtube_video_media_proxy.reset(); youtube_audio_media_proxy.reset(); @@ -2969,9 +2966,7 @@ namespace QuickMedia { if(youtube_audio_media_proxy) youtube_audio_media_proxy->stop(); - if(youtube_downloader_task.valid()) - youtube_downloader_task.cancel(); - + youtube_downloader_task.cancel(); youtube_video_media_proxy.reset(); youtube_audio_media_proxy.reset(); } diff --git a/src/plugins/MangaCombined.cpp b/src/plugins/MangaCombined.cpp index 1745ee0..5440871 100644 --- a/src/plugins/MangaCombined.cpp +++ b/src/plugins/MangaCombined.cpp @@ -23,10 +23,14 @@ namespace QuickMedia { int accumulated_sleep_time = 0; while(true) { + size_t num_dead_threads = 0; for(size_t i = 0; i < search_threads.size(); ++i) { auto &search_thread = search_threads[i]; - if(!search_thread.second.valid()) + if(!search_thread.second.valid()) { + if(!plugin_finished_state[i].second) + ++num_dead_threads; continue; + } if(!search_thread.second.ready()) continue; @@ -40,6 +44,9 @@ namespace QuickMedia { } } + if(num_dead_threads == search_threads.size()) + break; + size_t num_finished_plugins = 0; for(auto &f : plugin_finished_state) { if(f.second) @@ -58,7 +65,7 @@ namespace QuickMedia { break; } - int sleep_time_ms = 200; + int sleep_time_ms = 50; std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time_ms)); accumulated_sleep_time += sleep_time_ms; if(accumulated_sleep_time >= SEARCH_TIMEOUT_MILLISECONDS) { @@ -114,4 +121,11 @@ namespace QuickMedia { if(!page) return PluginResult::OK; return page->submit(title, url, result_tabs); } + + void MangaCombinedSearchPage::cancel_operation() { + for(auto &search_thread : search_threads) { + search_thread.second.cancel(); + } + search_threads.clear(); + } } \ No newline at end of file diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index 2fd193f..cd3fddd 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -1667,6 +1667,9 @@ R"END( const time_t time_now = time(nullptr); for(const std::string &channel_id : channel_ids) { + if(program_is_dead_in_current_thread()) + return PluginResult::OK; + subscription_load_tasks[async_task_index] = AsyncTask>([&channel_id, time_now]() -> std::vector { std::string website_data; DownloadResult result = download_to_string("https://www.youtube.com/feeds/videos.xml?channel_id=" + url_param_encode(channel_id), website_data, {}, false); -- cgit v1.2.3