我已经制作了一个非常简单的线程计时器类,并且考虑到MT代码的缺陷,我想要进行理智检查。这里的想法是启动一个线程然后连续循环等待一个变量。如果等待超时,则超过间隔,我们调用回调。如果变量已发出信号,则线程应该退出,我们不会调用回调。
我不确定的事情之一就是我的代码在析构函数中发生了什么,因为线程可以在那里连接(只是)。我可以在析构函数中加入一个线程以确保它已完成吗?
这是班级:
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;
};
我想更好的问题可能是要求某人指出一个非常简单的线程计时器,如果有一个已经可用的话。
答案 0 :(得分:2)
我可以加入析构函数中的线程以确保它已完成吗?
不仅可以,而且这种做法非常典型。如果线程实例在被销毁时是可连接的(即仍在运行),则会调用terminate
。
由于某种原因,结果总是超时。它似乎永远不会发出信号,因此永远不会停止。这是对的吗? notify_all应该取消阻止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;
...
通过这些更改,您的计时器应该可以正常工作,但确实意识到&#34; [std::condition_variable::wait_for
]由于调度或资源争用延迟而导致阻塞的时间超过timeout_duration&#34;,用{{3 }}
指向一个非常简单的线程计时器,如果有一个已在某处可用。
我不知道标准的c ++解决方案,但现代操作系统通常提供这种功能,或者至少可以用来构建它。有关示例,请参阅linux上的cppreference.com。