Я написал класс таймера, но он работает не так, как мне нужно. Может ли кто-нибудь сказать мне, что в этом плохого?
template<typename D, typename C>
class timer
{
public:
timer(D period, C&& callback)
{
std::thread t{[&](){
std::this_thread::sleep_for(period);
callback();
}};
t.detach();
}
};
int main()
{
timer t1(std::chrono::seconds(2), [](){
std::cout << "hello from 1\n";
});
timer t2(std::chrono::seconds(3), [](){
std::cout << "hello from 2\n";
});
std::this_thread::sleep_for(std::chrono::seconds(5));
}
Вывод только:
hello from 1
Где находится строка «Привет от 2»?
зачем тебе отсоединять нить таймера?
@ 463035818_is_not_an_ai, потому что, если его не отсоединить, функция завершения будет вызвана после выхода из конструктора
@Андрей, ты можешь избежать этого, сделав std::thread членом класса timer, а затем join() поток в деструкторе таймера
@RemyLebeau, да, я мог бы, но для чего? Будет ли это проще, чем использовать всего одну строку кода? В чем преимущество?
@Андрей, если ты отделишь тред, ты потеряешь к нему доступ. Отсоединять поток и не иметь возможности остановить его или подождать, если это необходимо, может быть опасно. Есть очень мало причин когда-либо отсоединять нить. Когда мне следует использовать std::thread::detach?





В вашем конструкторе:
timer(D period, C&& callback) { std::thread t{[&](){ std::this_thread::sleep_for(period); callback(); }}; t.detach(); }
period и callback уничтожаются, когда timer возвращается, а timer возвращается задолго до вызова callback и, возможно, даже до вызова sleep_for.
Исправление состоит в том, чтобы скопировать period и callback в функтор потока, чтобы эти копии оставались активными во время работы потока:
timer(D period, C&& callback)
{
std::thread t{[=](){
std::this_thread::sleep_for(period);
callback();
}};
t.detach();
}
Еще одна вещь, на которую следует обратить внимание, это то, что C&& не является ссылкой для пересылки. Либо конструктор следует превратить в шаблон, либо убрать callback при его захвате в лямбда-выражении.
Захват по ссылке и асинхронные обратные вызовы несовместимы.