线程计时器,中断睡眠(停止睡眠)

Rob*_*son 1 c++ multithreading timer

我想要一个合理可靠的线程计时器,因此我编写了一个计时器对象,该对象在线程上触发std :: function。我希望此计时器能够在到达下一个刻度之前停止运行;:: sleep无法实现的功能(至少我不认为可以)。

所以我要做的是将条件变量放在互斥锁上。如果条件超时,我将触发该事件。如果发出条件信号,则退出线程。因此Stop方法需要能够使线程停止和/或中断其等待,我认为这是它现在正在做的事情。

但是,这有问题。有时线程不是joinable(),并且有时条件超时后但进入等待状态之前发出信号。

我如何改善它并使之坚固?

以下是完整的仓库。这里的等待时间为10秒,但是程序应在创建Foo之后立即终止,然后立即销毁。有时会,但大多数时候不会。

#include <atomic>
#include <thread>
#include <future>
#include <sstream>
#include <chrono>
#include <iostream>

class Timer
{
public:

    Timer() {}

    ~Timer()
    {           
        Stop();
    }

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

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

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

    void Stop()
    {       
        terminate.notify_one();

        if(thread.joinable())
        {
            thread.join();
        }
    }

private:

    std::thread thread;
    std::mutex mutex;
    std::condition_variable terminate;
};

class Foo
{
public: 

    Foo()
    {
        timer = std::make_unique<Timer>();
        timer->Start(std::chrono::milliseconds(10000), std::bind(&Foo::Callback, this));
    }

    ~Foo()
    {

    }

    void Callback()
    {
        static int count = 0;

        std::ostringstream o;

        std::cout << count++ << std::endl;
    }

    std::unique_ptr<Timer> timer;
};


int main(void)
{
    {
        Foo foo;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*rtz 5

看到我的评论。您忘了实现线程正在等待的事物的状态,而互斥锁没有任何保护,线程也没有等待。条件变量是无状态的-您的代码必须跟踪您要通知线程的事物的状态。

这是固定的代码。请注意,互斥体保护stop,并且stop是线程正在等待的东西。

    class Timer
    {
    public:

        Timer() {}

        ~Timer()
        {           
            Stop();
        }

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

            {
                auto locked = std::unique_lock<std::mutex>(mutex);    
                stop = false;
            }

            thread = std::thread([=]()
            {
                auto locked = std::unique_lock<std::mutex>(mutex);    

                while (! stop) // We hold the mutex that protects stop
                {
                    auto result = terminate.wait_for(locked, interval);

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

        void Stop()
        {    
            {     
                // Set the predicate
                auto locked = std::unique_lock<std::mutex>(mutex);
                stop = true;
            }

            // Tell the thread the predicate has changed
            terminate.notify_one();

            if(thread.joinable())
            {
                thread.join();
            }
        }

    private:

        bool stop; // This is the thing the thread is waiting for
        std::thread thread;
        std::mutex mutex;
        std::condition_variable terminate;
    };
Run Code Online (Sandbox Code Playgroud)