From 537b8a836d3607eaa1af7bfa25dd9b9184bb1e73 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 29 Nov 2021 11:02:41 +0100 Subject: [PATCH] Merge bitcoin/bitcoin#23397: Avoid excessive lock contention in CCheckQueue::Add 459e208276a4d1457d37bf41c977e62caf05456d Exit early for an empty vChecks in CCheckQueue::Add (Hennadii Stepanov) c43aa623435a277a692dbde784e8a7146f5573e9 Avoid excessive lock contention in CCheckQueue::Add (Hennadii Stepanov) Pull request description: This PR significantly reduces lock contention in the `CCheckQueue` class by releasing a mutex before calling `std::condition_variable::notify_one` and `std::condition_variable::notify_all`. From C++ [docs](https://en.cppreference.com/w/cpp/thread/condition_variable/notify_one): > The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock. Related to: - #23167 - #23223 ACKs for top commit: martinus: ACK 459e208, codereview and tested. I first thought this introduced a segfault in `psbt_wallet_tests/psbt_updater_test` because that test failed for me, but thats a different issue fixed in #23403. vasild: ACK 459e208276a4d1457d37bf41c977e62caf05456d theStack: Code-review ACK 459e208276a4d1457d37bf41c977e62caf05456d Tree-SHA512: c197858656392ba3ebcd638d713cf93c9fb48b7b3bad193209490d2828f9c7e3ae4dee6f84674f2f34dceed894139562e29579ee7299e06756c8c990caddc5ed --- src/checkqueue.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/checkqueue.h b/src/checkqueue.h index 13f249431772e..3665d25594d58 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -167,16 +167,24 @@ class CCheckQueue //! Add a batch of checks to the queue void Add(std::vector& vChecks) { - LOCK(m_mutex); - for (T& check : vChecks) { - queue.push_back(T()); - check.swap(queue.back()); + if (vChecks.empty()) { + return; } - nTodo += vChecks.size(); - if (vChecks.size() == 1) + + { + LOCK(m_mutex); + for (T& check : vChecks) { + queue.emplace_back(); + check.swap(queue.back()); + } + nTodo += vChecks.size(); + } + + if (vChecks.size() == 1) { m_worker_cv.notify_one(); - else if (vChecks.size() > 1) + } else { m_worker_cv.notify_all(); + } } //! Stop all of the worker threads.