使用std::thread和std::chrono创建基本计时器

9

我正在尝试使用经典方法:start()和stop()实现一个基本计时器。我使用c++11中的std::thread和std::chrono。

  • Start方法。创建一个新线程休眠一段时间,然后执行给定的std::function。只要'running'标志为true,就重复此过程。
  • Stop方法。将'running'标志设置为false。

我创建并启动了一个Timer对象,每秒钟显示“Hello!”一次,然后我用另一个线程尝试停止计时器,但我无法停止计时器。计时器永远不会停止。

我认为问题出在th.join()[*]上,它会在线程完成之前停止执行。但是当我删除th.join()行时,显然程序在计时器开始计数之前就结束了。

那么,我的问题是如何在不停止其他线程的情况下运行线程?

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

using namespace std;

class Timer
{
    thread th;
    bool running = false;

public:
    typedef std::chrono::milliseconds Interval;
    typedef std::function<void(void)> Timeout;

    void start(const Interval &interval,
               const Timeout &timeout)
    {
        running = true;

        th = thread([=]()
        {
            while (running == true) {
                this_thread::sleep_for(interval);
                timeout();
            }
        });

// [*]
        th.join();
    }

    void stop()
    {
        running = false;
    }
};

int main(void)
{
    Timer tHello;
    tHello.start(chrono::milliseconds(1000),
                 []()
    {
        cout << "Hello!" << endl;
    });

    thread th([&]()
    {
        this_thread::sleep_for(chrono::seconds(2));
        tHello.stop();
    });

    th.join();

    return 0;
}

输出:

Hello!
Hello!
...
...
...
Hello!

作为一个旁白,根据我的经验尝试实现相同的功能时,使用条件变量(condition_variable)更高效(因为它专为这种情况而设计)。然而,这会让代码变得不太清晰。 - Klaim
2个回答

11

Timer::start中,你会在th中创建一个新线程,然后立即使用th.join()将其与join。实际上,只有当生成的线程退出时,start才会返回。当然,它永远也不会退出,因为在start返回之前没有任何东西会将running设置为false......

除非你打算等待线程完成,否则不要使用join。在这种情况下,在stop中设置running = false之后是正确的位置。

另外 - 虽然这并不是不正确的 - 但没有必要在main中创建另一个线程来调用this_thread::sleep_for。你可以直接在主线程中这样做:

int main()
{
    Timer tHello;
    tHello.start(chrono::milliseconds(1000), []{
        cout << "Hello!" << endl;
    });

    this_thread::sleep_for(chrono::seconds(2));
    tHello.stop();
}

1

stop方法中,不要将join放在start之后,而是将其放在running = false之后。然后stop方法将在线程完成之前有效等待。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接