如何等待另一个线程再次循环?

问题描述 投票:0回答:1

在我的 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吗?或者是否有其他更适合的同步原语?

或者我的“等待另一个线程的下一个循环迭代”的想法是已知的反模式吗?

c++ multithreading c++17 thread-synchronization
1个回答
0
投票

您只需要使用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();
}

上帝螺栓示例

© www.soinside.com 2019 - 2024. All rights reserved.