33 std::vector<configurator> configs;
37 work_item(
unsigned int id, std::vector<configurator> configs,
int start,
int count)
38 :
id{
id}, work_str{}, configs(std::move(configs)), start{start}, count{count}
43 std::condition_variable work_cond;
47 std::atomic<int> pending_work_count;
49 std::atomic<bool> should_exit;
51 std::deque<work_item> work_queue;
53 std::vector<std::thread> workers;
55 std::string *target_str_ptr;
57 std::mutex target_str_mutex;
61 worker_concurrent() : should_exit(
false), pending_work_count(0), target_str_ptr(
nullptr) {}
70 void initThreads()
noexcept
77 while (!worker_ptr->should_exit.load())
79 unique_lock<mutex> lock(worker_ptr->work_mtx);
81 worker_ptr->work_cond.wait(lock, [worker_ptr]
82 {
return worker_ptr->should_exit.load() || !worker_ptr->work_queue.empty(); });
84 if (worker_ptr->should_exit.load())
91 if (!worker_ptr->work_queue.empty())
94 auto temp_worker = std::move(worker_ptr->work_queue.front());
96 worker_ptr->work_queue.pop_front();
100 worker_ptr->do_work(temp_worker);
104 if (--worker_ptr->pending_work_count <= 0)
106 worker_ptr->work_cond.notify_one();
112 static constexpr auto NUM_WORKERS = 4;
115 for (
auto w{0}; w < NUM_WORKERS; w++)
118 workers.emplace_back(thread_func,
this);
122 void generate(
const std::vector<configurator> &configs, std::string &target_str)
noexcept
127 target_str_ptr = &target_str;
130 unique_lock<std::mutex> lock(this->work_mtx);
134 static constexpr auto BLOCK_COUNT = 4;
136 size_t items_per_worker = configs.size() / BLOCK_COUNT;
137 size_t remaining_items = configs.size() % BLOCK_COUNT;
139 size_t current_index = 0;
141 for (
auto w{0}; w < BLOCK_COUNT; w++)
143 size_t start_index = current_index;
146 size_t count = items_per_worker + (w < remaining_items ? 1 : 0);
151 std::vector<configurator> worker_configs;
152 for (
size_t i = start_index; i < start_index + count && i < configs.size(); ++i)
154 worker_configs.push_back(configs[i]);
157 work_queue.emplace_back(
static_cast<unsigned int>(w), std::move(worker_configs),
static_cast<int>(start_index),
static_cast<int>(count));
160 current_index += count;
163 this->pending_work_count.store(
static_cast<int>(work_queue.size()));
166 this->work_cond.notify_all();
169 void wait_for_completion()
noexcept
173 unique_lock<mutex> lock(work_mtx);
174 work_cond.wait(lock, [&]
175 {
return pending_work_count.load() <= 0; });
178 void do_work(work_item &item)
noexcept
182 for (
const auto &config : item.configs)
184 item.work_str += create(config);
188 if (target_str_ptr && !item.work_str.empty())
190 lock_guard<mutex> lock(target_str_mutex);
191 *target_str_ptr += item.work_str;
195 void cleanup()
noexcept
198 std::lock_guard<std::mutex> lock(work_mtx);
202 pending_work_count = 0;
205 work_cond.notify_all();
207 for (
auto &t : workers)