我已经整理了一个简单的c ++计时器类,它应该定期从SO上的各种示例调用给定的函数,如下所示:
#include <functional>
#include <chrono>
#include <future>
#include <cstdio>
class CallBackTimer
{
public:
CallBackTimer()
:_execute(false)
{}
void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([&]()
{
while (_execute) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}
void stop()
{
_execute = false;
}
private:
bool _execute;
};
Run Code Online (Sandbox Code Playgroud)
现在我想从C++类中调用它,如下所示
class Processor()
{
void init()
{
timer.start(25, std::bind(&Processor::process, this));
}
void process()
{
std::cout << "Called" << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
但是,这会调用错误
terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call
Run Code Online (Sandbox Code Playgroud)
Mik*_*son 21
代码中的问题是你的"start"函数中的lambda表达式使用[&]语法通过引用捕获局部变量.这意味着lambda 通过引用捕获interval和func变量,它们都是start()函数的局部变量,因此,它们在从该函数返回后消失.但是,从该函数返回后,lambda在分离的线程内仍然存在.那是当你得到"bad-function-call"异常时,因为它试图func通过引用不再存在的对象进行调用.
您需要做的是使用[=]lambda上的语法按值捕获局部变量,如下所示:
void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([=]()
{
while (_execute) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}
Run Code Online (Sandbox Code Playgroud)
这在我尝试时有效.
或者,您还可以更明确地列出要捕获的值(我通常建议使用lambdas):
void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([this, interval, func]()
{
while (_execute) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}
Run Code Online (Sandbox Code Playgroud)
编辑
正如其他人所指出的那样,使用分离的线程并不是一个很好的解决方案,因为你很容易忘记停止线程而你无法检查它是否已经在运行.此外,您应该将_execute标志设置为原子,以确保它不会被优化,并且读/写是线程安全的.你可以这样做:
class CallBackTimer
{
public:
CallBackTimer()
:_execute(false)
{}
~CallBackTimer() {
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
}
void stop()
{
_execute.store(false, std::memory_order_release);
if( _thd.joinable() )
_thd.join();
}
void start(int interval, std::function<void(void)> func)
{
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
_execute.store(true, std::memory_order_release);
_thd = std::thread([this, interval, func]()
{
while (_execute.load(std::memory_order_acquire)) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
});
}
bool is_running() const noexcept {
return ( _execute.load(std::memory_order_acquire) &&
_thd.joinable() );
}
private:
std::atomic<bool> _execute;
std::thread _thd;
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18405 次 |
| 最近记录: |