C ++ 11:定期调用C ++函数 [英] C++ 11: Calling a C++ function periodically
问题描述
我整理了一个简单的c ++计时器类,该类应该从SO上的各种示例中定期调用给定函数,如下所示:
I have put together a simple c++ timer class that is supposed to call a given function periodically from various examples on SO as follows:
#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;
};
现在我想从C ++类中调用它,如下所示:L
Now I want to call this from a C++ class as followsL
class Processor()
{
void init()
{
timer.start(25, std::bind(&Processor::process, this));
}
void process()
{
std::cout << "Called" << std::endl;
}
};
但是,这会出现错误
terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call
推荐答案
代码中的问题是, start函数中的lambda表达式使用<$ c $通过引用捕获局部变量。 c> [&] 语法。这意味着lambda通过引用捕获 interval
和 func
变量,它们都是<$ c的局部变量$ c> start()函数,因此,它们从该函数返回后便消失了。但是,从该函数返回后,lambda仍然在分离的线程中仍然存在。那是当您收到错误函数调用异常的时候,因为它试图通过引用不再存在的对象来调用 func
。
The problem in your code is that your lambda expression inside your "start" function captures the local variables by reference, using the [&]
syntax. This means that the lambda captures the interval
and func
variables by reference, which are both local variables to the start()
function, and thus, they disappear after returning from that function. But, after returning from that function, the lambda is still alive inside the detached thread. That's when you get the "bad-function-call" exception because it tries to call func
by reference to an object that no longer exists.
您需要做的是按值捕获局部变量,在lambda上使用 [=]
语法,如下所示:
What you need to do is capture the local variables by value, with the [=]
syntax on the lambda, as so:
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();
}
在我尝试时可以使用。
或者,您也可以更明确地列出要捕获的值(我通常推荐给lambda):
Or, you could also list out the values you want to capture more explicitly (which I generally recommend for 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();
}
编辑
正如其他人所指出的那样,使用分离的线程并不是一个很好的解决方案,因为您很容易忘记停止线程,并且无法检查它是否已在运行。另外,您可能应该使 _execute
标志成为原子标志,以确保它不会被优化,并且读/写是线程安全的。您可以改为:
As others have pointed out, the use of a detached thread is not a great solution because you could easily forget to stop the thread and you have no way to check if it's already running. Also, you should probably make the _execute
flag atomic, just to be sure it doesn't get optimized out and that the reads / writes are thread-safe. You could do this instead:
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;
};
这篇关于C ++ 11:定期调用C ++函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!