简单的线程计时器,请进行健全性检查

Simple threaded timer, sanity check please

我制作了一个非常简单的线程计时器 class 考虑到 MT 代码的缺陷,我想请您进行完整性检查。这里的想法是启动一个线程,然后不断地循环等待一个变量。如果等待超时,则超出间隔,我们调用回调。如果变量被通知,线程应该退出,我们不调用回调。

我不确定的一件事是我的代码在析构函数中发生了什么,假设线程可能在那里是可连接的(只是)。我可以在析构函数中加入线程以确保它已完成吗?

这是class:

class TimerThreaded
{
public:

    TimerThreaded() {}
    ~TimerThreaded()
    {           
        if (MyThread.joinable())
            Stop();             
    }

    void Start(std::chrono::milliseconds const & interval, std::function<void(void)> const & callback)
    {   
        if (MyThread.joinable())
            Stop();

        MyThread = std::thread([=]()
        {
            for (;;)
            {
                auto locked = std::unique_lock<std::mutex>(MyMutex);
                auto result = MyTerminate.wait_for(locked, interval);

                if (result == std::cv_status::timeout)
                    callback();
                else
                    return;
            }
        });
    }

    void Stop()
    {
        MyTerminate.notify_all();
    }

private:

    std::thread MyThread;
    std::mutex MyMutex;
    std::condition_variable MyTerminate;
};

我想一个更好的问题可能是让某人向我指出一个非常简单的线程计时器,如果某个地方已经可用的话。

Can I join a thread in a destructor to make sure it's finished?

不仅您可以,而且这样做很正常。如果线程实例在销毁时是可连接的(即仍然 运行),将调用 terminate

For some reason result is always timeout. It never seems to get signalled and so never stops. Is it correct? notify_all should unblock the wait_for?

只有线程恰好在cv上才能解除阻塞。您可能正在做的是调用 Start,然后在线程启动 运行 并开始等待之前立即调用 Stop(或者可能在 callback 是 运行 时) .在那种情况下,线程永远不会被通知。

您的代码还有另一个问题。即使您没有显式调用 notify_X,阻塞的线程也可能在某些实现中被虚假地唤醒。那会导致您的计时器无缘无故地随机停止。

我建议您添加一个标志变量,指示是否已调用 Stop。这将解决上述两个问题。这是使用条件变量的典型方式。我什至为您编写了代码:

class TimerThreaded
{
...
        MyThread = std::thread([=]()
        {
            for (;;)
            {
                auto locked = std::unique_lock<std::mutex>(MyMutex);
                auto result = MyTerminate.wait_for(locked, interval);

                if (stop_please)
                    return;
                if (result == std::cv_status::timeout)
                    callback();
            }
        });
....
    void Stop()
    {
        {
            std::lock_guard<std::mutex> lock(MyMutex);
            stop_please = true;
        }
        MyTerminate.notify_all();
        MyThread.join();
    }

...
private:
    bool stop_please = false;
...

通过这些更改,您的计时器应该可以工作,但请注意,用 cppreference.com.

point me towards a very simple threaded timer, if there's one already available somewhere.

我不知道标准的 c++ 解决方案,但现代操作系统通常提供这种功能或至少提供可用于构建它的部分。有关示例,请参阅 linux 上的 timerfd_create