我想要一个相当可靠的线程计时器,所以我写了一个计时器对象,它在一个线程上触发一个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;
}
答案 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;
};