пробл em в вашем коде является то, что ваше выражение лямбда внутри вашей «стартовой» функции захватывает локальные переменные по ссылке, используя синтаксис [&]
. Это означает, что лямбда фиксирует переменные interval
и func
по ссылке, которые являются как локальными переменными, так и функцией start()
, и, таким образом, они исчезают после возвращения из этой функции. Но, вернувшись с этой функции, лямбда все еще жива внутри отдельной нити. Именно тогда вы получаете исключение «bad-function-call», потому что оно пытается вызвать func
ссылкой на объект, который больше не существует.
Что вам нужно сделать, это захватить локальные переменные значения, с [=]
синтаксисом на лямбда, а так:
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 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();
}
EDIT
Как уже отмечалось, использование отделяемой нити не является отличным решением, потому что вы можете легко забыть остановить поток, и у вас нет возможности проверить, запущен ли он. Кроме того, вы должны, вероятно, сделать флаг _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;
};
Работает ли это с отдельно стоящей функцией 'void foo() {}'? – stefan
Действительно ли вы дожидаетесь окончания нитки в какой-то момент? Вы полностью отделите его, так что вы уверены, что ваш основной поток просто не уничтожил соответствующий объект «Процессор»? – KillianDS
@KillianDS это, скорее всего, что происходит. Лука, вы должны отправить сообщение [MCVE] (http://stackoverflow.com/help/mcve). Что произойдет, если вы '.join()' поток? – vsoftco