使用条件变量的基于精确计时器的处理实现

发布于 2025-01-11 13:22:06 字数 1139 浏览 0 评论 0原文

我需要一个线程来准确地每秒执行一次处理。假设如果工作线程正忙于某些需要超过一秒的操作,我希望工作线程错过1s到期通知并在下一个周期执行处理。

我正在尝试使用两个线程来实现这一点。一个线程是工作线程,另一个线程休眠一秒并通过条件变量通知工作线程。

代码如下所示

工作线程

    while(!threadExit){
        std::unique_lock<std::mutex> lock(mutex);
        // Block until a signal is received
        condVar_.wait(lock, [this](){return (threadExit || performProc);)});

        if(threadExit_){
            break;
        }

        // Perform the processing
        ..............
     }

定时器线程

    while(!threadExit)
    {
        {
            std::unique_lock<std::mutex> lock(mutex);
            performProc= false;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        if(threadExit){
            break;
        }

        {
            std::unique_lock<std::mutex> lock(mutex);
            performProc= true;
        }
        condVar.notify_one();
    }

请注意,变量 threadExit 是由主线程在互斥锁下设置的,并通知给工作线程。计时器线程在唤醒时可以看到此标志(这对于我的实现来说应该没问题)

您认为在工作线程将其视为 true 之前 performProc 可能会再次设置为 false 吗?如果是,您能否说明如何解决这个问题?谢谢!

I need a thread to perform processing every one second accurately. Suppose if the worker thread is busy on some operation that takes more than one second, I want the worker thread to miss the 1s expiry notification and perform the processing in the next cycle.

I am trying to implement this using two threads. One thread is a worker thread, another thread sleeps for one second and notifies the worker thread via condition variable.

Code is shown below

Worker thread

    while(!threadExit){
        std::unique_lock<std::mutex> lock(mutex);
        // Block until a signal is received
        condVar_.wait(lock, [this](){return (threadExit || performProc);)});

        if(threadExit_){
            break;
        }

        // Perform the processing
        ..............
     }

Timer thread

    while(!threadExit)
    {
        {
            std::unique_lock<std::mutex> lock(mutex);
            performProc= false;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        if(threadExit){
            break;
        }

        {
            std::unique_lock<std::mutex> lock(mutex);
            performProc= true;
        }
        condVar.notify_one();
    }

Please note the variable threadExit is set by the main thread under the mutex lock and notified to worker thread. The timer thread can see this flag when it wakes up(which should be fine for my implementation)

Do you think performProc may set to false again before the worker thread sees it as true? If yes, can you please throw some light on how to tackle this problem? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

妞丶爷亲个 2025-01-18 13:22:06

除非threadExitatomic,否则代码会表现出未定义的行为(竞争条件)。对 threadExit 的所有访问都必须受到互斥锁的保护,因此还要读取 while(!threadExit)if(threadExit)...

但没有必要这样做。如果使用 sleep_until<,则可以在同一线程中运行所有内容/a> (和稳定的时钟)而不是 sleep_for

#include <chrono>
#include <iostream>
#include <thread>

using namespace std::literals;

void do_work() {
    std::cout << "Work @ " << std::chrono::system_clock::now() << std::endl;
}

int main() {
    while (true) {
        auto t = ceil<std::chrono::seconds>(std::chrono::steady_clock::now() + 600ms);
        std::this_thread::sleep_until(t);
        do_work();
    }
}

输出:

Work @ 2022-03-04 09:56:51.0148904
Work @ 2022-03-04 09:56:52.0134687
Work @ 2022-03-04 09:56:53.0198704
Work @ 2022-03-04 09:56:54.0010437
Work @ 2022-03-04 09:56:55.0148975
. . .

Unless threadExit is atomic, the code exhibits undefined behavior (race condition). All accesses to threadExit must be protected by a mutex, so also reads in while(!threadExit) and if(threadExit)....

But there's no need to do any of this. You can run everything in the same thread if you use sleep_until (and a steady clock) instead of sleep_for.

#include <chrono>
#include <iostream>
#include <thread>

using namespace std::literals;

void do_work() {
    std::cout << "Work @ " << std::chrono::system_clock::now() << std::endl;
}

int main() {
    while (true) {
        auto t = ceil<std::chrono::seconds>(std::chrono::steady_clock::now() + 600ms);
        std::this_thread::sleep_until(t);
        do_work();
    }
}

Output:

Work @ 2022-03-04 09:56:51.0148904
Work @ 2022-03-04 09:56:52.0134687
Work @ 2022-03-04 09:56:53.0198704
Work @ 2022-03-04 09:56:54.0010437
Work @ 2022-03-04 09:56:55.0148975
. . .
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文