5#ifndef BITCOIN_CHECKQUEUE_H
6#define BITCOIN_CHECKQUEUE_H
32template <typename T, typename R = std::remove_cvref_t<decltype(std::declval<T>()().value())>>
75 std::vector<T> vChecks;
77 unsigned int nNow = 0;
78 std::optional<R> local_result;
85 if (local_result.has_value() && !m_result.has_value()) {
86 std::swap(local_result, m_result);
89 if (nTodo == 0 && !fMaster) {
98 while (queue.empty() && !m_request_stop) {
99 if (fMaster && nTodo == 0) {
101 std::optional<R> to_return = std::move(m_result);
103 m_result = std::nullopt;
111 if (m_request_stop) {
121 nNow = std::max(1U, std::min(
nBatchSize, (
unsigned int)queue.size() / (nTotal + nIdle + 1)));
122 auto start_it = queue.end() - nNow;
123 vChecks.assign(std::make_move_iterator(start_it), std::make_move_iterator(queue.end()));
124 queue.erase(start_it, queue.end());
126 do_work = !m_result.has_value();
130 for (
T& check : vChecks) {
131 local_result = check();
132 if (local_result.has_value())
break;
144 explicit CCheckQueue(
unsigned int batch_size,
int worker_threads_num)
147 LogInfo(
"Script verification uses %d additional threads", worker_threads_num);
149 for (
int n = 0; n < worker_threads_num; ++n) {
174 if (vChecks.empty()) {
180 queue.insert(queue.end(), std::make_move_iterator(vChecks.begin()), std::make_move_iterator(vChecks.end()));
181 nTodo += vChecks.size();
184 if (vChecks.size() == 1) {
207template <typename T, typename R = std::remove_cvref_t<decltype(std::declval<T>()().value())>>
228 void Add(std::vector<T>&& vChecks)
230 m_queue.Add(std::move(vChecks));
CCheckQueueControl & operator=(const CCheckQueueControl &)=delete
CCheckQueueControl(const CCheckQueueControl &)=delete
CCheckQueueControl()=delete
~CCheckQueueControl() UNLOCK_FUNCTION()
UniqueLock< Mutex > m_lock
CCheckQueue< T, R > & m_queue
CCheckQueueControl(CCheckQueue< T > &queueIn) EXCLUSIVE_LOCK_FUNCTION(queueIn.m_control_mutex)
std::optional< R > Complete()
void Add(std::vector< T > &&vChecks)
Queue for verifications that have to be performed.
bool m_request_stop GUARDED_BY(m_mutex)
std::optional< R > Complete() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
unsigned int nTodo GUARDED_BY(m_mutex)
Number of verifications that haven't completed yet.
std::vector< T > queue GUARDED_BY(m_mutex)
CCheckQueue(const CCheckQueue &)=delete
void Add(std::vector< T > &&vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a batch of checks to the queue.
int nIdle GUARDED_BY(m_mutex)
The number of workers (including the master) that are idle.
CCheckQueue & operator=(CCheckQueue &&)=delete
int nTotal GUARDED_BY(m_mutex)
The total number of workers (including the master).
CCheckQueue(unsigned int batch_size, int worker_threads_num)
Create a new check queue.
std::optional< R > Loop(bool fMaster) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Internal function that does bulk of the verification work.
std::condition_variable m_worker_cv
std::vector< std::thread > m_worker_threads
const unsigned int nBatchSize
std::optional< R > m_result GUARDED_BY(m_mutex)
The temporary evaluation result.
CCheckQueue(CCheckQueue &&)=delete
std::condition_variable m_master_cv
CCheckQueue & operator=(const CCheckQueue &)=delete
Wrapper around std::unique_lock style lock for MutexType.
#define T(expected, seed, data)
void ThreadRename(const std::string &)
#define WAIT_LOCK(cs, name)
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
#define WITH_LOCK(cs, code)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define EXCLUSIVE_LOCK_FUNCTION(...)
#define UNLOCK_FUNCTION(...)