在我的 C++17 应用程序中,我有一个线程运行无限循环,在每次迭代中执行一些工作(每次需要几秒钟)。
现在我想在另一个线程(或多个其他线程)中等待,直到下一个循环迭代完成。
这是一个例子:
#include <atomic>
#include <chrono>
#include <thread>
void notify_any_waiting_threads()
{
// TODO: how to implement this?
}
void wait_for_worker_thread_iteration()
{
// TODO: how to implement this?
}
void do_work()
{
std::this_thread::sleep_for(std::chrono::seconds(1)); // simulate some work
}
std::atomic_bool kill_worker_thread = false;
std::atomic_bool worker_should_be_idle = false;
void worker_thread_function()
{
while (!kill_worker_thread) {
if (worker_should_be_idle) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // sleep a bit, to avoid wasting CPU time
} else {
do_work();
}
notify_any_waiting_threads();
}
}
void observer_thread_function()
{
worker_should_be_idle = true;
wait_for_worker_thread_iteration();
// at this point I want to be sure that the worker thread does not execute do_work() any more
}
int main()
{
std::thread worker_thread(worker_thread_function);
std::this_thread::sleep_for(std::chrono::milliseconds(1800)); // simulate that observer thread does not start immediately
std::thread observer_thread_1(observer_thread_function);
// just some cleanup (not relevant for the question I think)
observer_thread_1.join();
kill_worker_thread = true;
worker_thread.join();
}
实施
notify_any_waiting_threads()
和 wait_for_worker_thread_iteration()
的最佳方法是什么?
我正在考虑使用
std::condition_variable
;但是在 std::condition_variable::wait()
的谓词中检查的“条件”是什么?实际上,我可以在每次迭代中通知condition_variable吗?或者是否有其他更适合的同步原语?
或者我的“等待另一个线程的下一个循环迭代”的想法是已知的反模式吗?
您只需要使用std::condition_variable,当迭代计数发生变化时会收到通知。
#include <atomic>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <iostream>
struct IterationCounter
{
std::condition_variable cv;
int count = 0;
std::mutex m;
void wait()
{
std::unique_lock lk(m);
auto old_value = count;
cv.wait(lk, [&] { return old_value != count; });
}
void increment()
{
{
std::unique_lock lk(m);
count++;
}
cv.notify_all();
}
};
void notify_any_waiting_threads(IterationCounter& counter)
{
counter.increment();
}
void wait_for_worker_thread_iteration(IterationCounter& counter)
{
counter.wait();
}
void do_work()
{
std::this_thread::sleep_for(std::chrono::seconds(1)); // simulate some work
}
std::atomic_bool kill_worker_thread = false;
std::atomic_bool worker_should_be_idle = false;
void worker_thread_function(IterationCounter& counter)
{
while (!kill_worker_thread) {
if (worker_should_be_idle) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // sleep a bit, to avoid wasting CPU time
}
else {
do_work();
}
notify_any_waiting_threads(counter);
}
std::cout << "stopped!\n";
}
void observer_thread_function(IterationCounter& counter)
{
worker_should_be_idle = true;
wait_for_worker_thread_iteration(counter);
std::cout << "notified!\n";
kill_worker_thread = true;
}
int main()
{
IterationCounter counter;
std::thread worker_thread(worker_thread_function, std::ref(counter));
std::this_thread::sleep_for(std::chrono::milliseconds(1800)); // simulate that observer thread does not start immediately
std::thread observer_thread_1(observer_thread_function, std::ref(counter));
// just some cleanup (not relevant for the question I think)
observer_thread_1.join();
kill_worker_thread = true;
worker_thread.join();
}