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

时间:2015-09-21 10:37:07

标签: c++ multithreading timer

我想要一个相当可靠的线程计时器,所以我写了一个计时器对象,它在一个线程上触发一个std :: function。我想让这个计时器能够在它到达下一个滴答之前停止;你不能做的事情::睡觉(至少我认为你不能)。

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

然而,这有问题。有时线程不是可连接的(),有时在超时之后但在它进入等待状态之前,会发出信号。

如何改善这一点并使其健壮?

以下是完整的回购。这里的等待时间是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;
}

1 个答案:

答案 0 :(得分:4)

查看我的评论。你忘了实现线程正在等待的东西的状态,让互斥锁无需保护,线程无需等待。条件变量是无状态的 - 您的代码必须跟踪您正在通知线程的更改的事物的状态。

这是修复的代码。请注意,互斥锁保护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;
    };