dnfdaemon: Replace busy-wait loop with condition variable

Using condition variable to inform the cleanup thread is more efficient
then busy-wait loop.
This commit is contained in:
Marek Blaha 2024-10-23 13:11:20 +02:00
parent bed44b77c6
commit 1bf924cf21
2 changed files with 33 additions and 26 deletions

View File

@ -29,12 +29,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
ThreadsManager::ThreadsManager() {
// collecting finished worker threads
running_threads_collector = std::thread([this]() {
while (!finish_collector) {
join_threads(true);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
running_threads_collector = std::thread(&ThreadsManager::join_threads, this);
}
ThreadsManager::~ThreadsManager() {
@ -49,30 +44,40 @@ void ThreadsManager::register_thread(std::thread && thread) {
void ThreadsManager::mark_thread_finished(std::thread::id thread_id) {
std::lock_guard<std::mutex> lock(running_threads_mutex);
finished_threads.emplace_back(std::move(thread_id));
signal_finished_thread.notify_one();
}
void ThreadsManager::join_threads(const bool only_finished) {
std::vector<std::thread> to_be_joined{};
{
std::lock_guard<std::mutex> lock(running_threads_mutex);
for (auto thread = running_threads.begin(); thread < running_threads.end();) {
auto in_finished = std::find(finished_threads.begin(), finished_threads.end(), thread->get_id());
if (thread->joinable() && (!only_finished || (in_finished != finished_threads.end()))) {
to_be_joined.push_back(std::move(*thread));
running_threads.erase(thread);
if (in_finished != finished_threads.end()) {
finished_threads.erase(in_finished);
void ThreadsManager::join_threads() {
while (true) {
std::unique_lock<std::mutex> lock(running_threads_mutex);
while (!finish_collector && finished_threads.empty()) {
signal_finished_thread.wait(lock);
}
std::vector<std::thread> to_be_joined{};
{
for (auto thread = running_threads.begin(); thread < running_threads.end();) {
auto in_finished = std::find(finished_threads.begin(), finished_threads.end(), thread->get_id());
if (thread->joinable() && (finish_collector || (in_finished != finished_threads.end()))) {
to_be_joined.push_back(std::move(*thread));
running_threads.erase(thread);
if (in_finished != finished_threads.end()) {
finished_threads.erase(in_finished);
}
} else {
++thread;
}
} else {
++thread;
}
}
}
lock.unlock();
for (auto thread = to_be_joined.begin(); thread < to_be_joined.end(); ++thread) {
// join the thread and remove it from registry
thread->join();
for (auto thread = to_be_joined.begin(); thread < to_be_joined.end(); ++thread) {
// join the thread and remove it from registry
thread->join();
}
if (finish_collector) {
break;
}
}
}
@ -82,7 +87,7 @@ void ThreadsManager::finish() {
}
// join all threads
finish_collector = true;
join_threads(false);
signal_finished_thread.notify_all();
running_threads_collector.join();
}

View File

@ -28,6 +28,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <sdbus-c++/sdbus-c++.h>
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <optional>
@ -42,7 +43,7 @@ public:
void register_thread(std::thread && thread);
void mark_thread_finished(std::thread::id thread_id);
void current_thread_finished() { mark_thread_finished(std::this_thread::get_id()); };
void join_threads(const bool only_finished);
void join_threads();
void finish();
template <class S>
@ -198,6 +199,7 @@ public:
}
private:
std::condition_variable signal_finished_thread;
std::mutex running_threads_mutex;
// flag whether to break the finished threads collector infinite loop
std::atomic<bool> finish_collector{false};