aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-07-21 14:46:48 +0200
committerdec05eba <dec05eba@protonmail.com>2021-07-21 14:46:48 +0200
commita76dabb12734154177a78033324b40365e7c6f21 (patch)
treedab1d6b997ba283dfcc7f9dd12adee96dd631dc2
parent3c16cb376669e4ae500d22529b40112c761088c0 (diff)
Fix freeze on search reset in manga combined plugin. Fix multithreading issues in AsyncTask
-rw-r--r--include/AsyncTask.hpp31
-rw-r--r--plugins/MangaCombined.hpp1
-rw-r--r--plugins/Page.hpp1
-rw-r--r--src/Downloader.cpp4
-rw-r--r--src/QuickMedia.cpp11
-rw-r--r--src/plugins/MangaCombined.cpp18
-rw-r--r--src/plugins/Youtube.cpp3
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 <thread>
#include <future>
+#include <mutex>
namespace QuickMedia {
template <class T, class... Args>
@@ -13,6 +14,7 @@ namespace QuickMedia {
AsyncTask() = default;
AsyncTask(CallbackFunc callback_func, Args&&... args) {
+ std::lock_guard<std::mutex> lock(mutex);
std::promise<T> promise;
future = promise.get_future();
thread = std::thread(&AsyncTask::thread_handler, this, std::move(promise), std::move(callback_func), std::forward<Args>(args)...);
@@ -20,12 +22,14 @@ namespace QuickMedia {
AsyncTask(AsyncTask &&other) {
cancel();
+ std::lock_guard<std::mutex> lock(mutex);
thread = std::move(other.thread);
future = std::move(other.future);
}
AsyncTask& operator=(AsyncTask &&other) {
cancel();
+ std::lock_guard<std::mutex> 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<std::mutex> lock(mutex);
return future.valid();
}
bool ready() {
+ std::lock_guard<std::mutex> 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<std::mutex> lock(mutex);
+ if constexpr(std::is_same<T, void>::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<std::mutex> 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<T> 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<Tab> &result_tabs) override;
sf::Vector2i get_thumbnail_max_size() override { return sf::Vector2i(101, 141); };
+ void cancel_operation() override;
private:
std::vector<MangaPlugin> search_pages;
std::vector<MangaCombinedSearchThread> 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<Body> create_body(bool plain_text_list = false, bool prefer_card_view = false);
std::unique_ptr<SearchBar> 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<MediaChapter> 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<std::vector<YoutubeSubscriptionTaskResult>>([&channel_id, time_now]() -> std::vector<YoutubeSubscriptionTaskResult> {
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);