Я написал класс таймера, но он работает не так, как мне нужно. Может ли кто-нибудь сказать мне, что в этом плохого?
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
при его захвате в лямбда-выражении.
Захват по ссылке и асинхронные обратные вызовы несовместимы.