PROBL W twoim kodzie jest to, że twoje wyrażenie lambda wewnątrz twojej funkcji "start" przechwytuje zmienne lokalne przez odniesienie, używając składni [&]
. Oznacza to, że lambda przechwytuje zmienne interval
i func
przez odniesienie, które są zarówno zmiennymi lokalnymi do funkcji start()
, a zatem znikają po powrocie z tej funkcji. Ale po powrocie z tej funkcji lambda wciąż żyje wewnątrz oddzielonej nici. Wtedy pojawia się wyjątek "zła funkcja wywołania", ponieważ próbuje wywołać func
przez odniesienie do obiektu, który już nie istnieje.
Co trzeba zrobić, to uchwycić zmiennych lokalnych według wartości, ze składnią [=]
na lambda, a więc:
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();
}
To działa, gdy próbuję go.
Albo, można również wymienić się wartości, które chcesz uchwycić bardziej wyraźny (które generalnie zalecane dla lambda):
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
Jak inni zwrócili uwagę, korzystanie oderwanego wątku nie jest doskonałym rozwiązaniem, ponieważ łatwo można zapomnieć zatrzymać wątek i nie można sprawdzić, czy już działa. Powinieneś także zrobić atomową flagę _execute
, aby upewnić się, że nie zostanie ona zoptymalizowana, a odczyty/zapisy są wątkowane. Zamiast tego można to zrobić:
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;
};
Czy działa z wolnostojącą funkcją 'void foo() {}'? – stefan
Czy rzeczywiście czekasz na zakończenie wątku? Całkowicie go odłączyłeś, więc czy jesteś pewien, że główny wątek po prostu nie zniszczył już odpowiedniego obiektu 'Procesor'? – KillianDS
@KillianDS najprawdopodobniej to, co się dzieje. Luca, powinieneś opublikować [MCVE] (http://stackoverflow.com/help/mcve). Co się stanie, jeśli '.join()' wątek? – vsoftco