У меня есть функция, которая должна запланировать задачу в цикле событий libuv. Моя идея состояла в том, чтобы создать таймер с тайм-аутом 0 мс. Я пробовал следующий код:
void myFunction() {
...
uv_timer_t* timer = new uv_timer_t();
uv_timer_init(uv_default_loop(), timer);
uv_timer_start(timer, [&](uv_timer_t* timer, int status) {
// Scheduled task
}, 0, 0);
}
Этот подход работает хорошо, но проблема в том, что динамически распределенный таймер никогда не будет освобожден. Я попытался освободить таймер в обратном вызове, но это привело к ошибке сегментации:
void myFunction() {
...
uv_timer_t* timer = new uv_timer_t();
uv_timer_init(uv_default_loop(), timer);
uv_timer_start(timer, [&](uv_timer_t* timer, int status) {
// Scheduled task
delete timer;
}, 0, 0);
}
Я также пытался позвонить uv_timer_stop(timer);
а также uv_unref((uv_handle_t*) timer);
до фактического освобождения памяти, но ошибка сегментации все еще повторяется.
У меня была такая же проблема, и вот способ, которым вы справляетесь с этим:
Во-первых, вы захотите создать обратный вызов, когда ваш дескриптор таймера закроется:
void on_timer_close_complete(uv_handle_t* handle)
{
free(handle);
}
Обратите внимание, что дескриптор будет освобожден в обратном вызове.
Когда вы идете, чтобы остановить и освободить свой таймер, вы сделаете это так:
uv_timer_stop(pTimerHandle);
uv_close((uv_handle_t *)pTimerHandle,on_timer_close_complete);
Часть, которая не является интуитивной, является uv_close()
вызов. Я не думаю, что видел это где-нибудь в документации. Я смог понять это только следуя источнику.
Таким образом, libuv выполнит ваш обратный вызов, когда это будет сделано с таймером, и затем вы сможете безопасно его освободить в этом обратном вызове.
Основываясь на ответе @IntelliAdmin, если вы не хотите закрывать его самостоятельно и просто хотите, чтобы он закрывался, когда на него больше нет ссылок, вы можете использовать умные указатели:
template<typename T>
using deleted_unique_ptr = std::unique_ptr<T, std::function<void( T* )>>;deleted_unique_ptr<uv_timer_t> timer = deleted_unique_ptr<uv_timer_t>( new uv_timer_t, [&]( uv_timer_t *timerhandl ) {
uv_close( reinterpret_cast<uv_handle_t *>( timerhandl ), OnTimerClose );
});
Затем для обратного вызова просто удалите указатель:
void OnTimerClose( uv_handle_t *handle )
{
delete handle;
}