- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
class session {
public:
session(int id, boost::asio::io_service &io_service) :
id(id),
timer(io_service)
{
timer.expires_from_now(session_timeout);
timer.async_wait(boost::bind(&session::on_timeout, this, _1));
}
void on_timeout(const boost::system::error_code &error) {
if (error)
return;
std::cout << "Session timed out " << id << std::endl;
}
private:
int id;
boost::asio::deadline_timer timer;
};
std::map<boost::asio::ip::udp::endpoint, boost::shared_pointer<session> > sessions;
sessions.erase(endpoint) приводит к небольшому насилию над трупом сессии... Ничего конечно не вылетает, и никогда не сломается, но совесть мучает, неприятно пользоваться UB'ом.
?
т.е. каждый таймер имеет четкую метку во времени, когда надо сработать - и недостаток основной специализации asio::deadline_timer в том, что она построена поверх posix_time, т.е. даты-времени
при совпадении пары условий (зависит от реализации в конкретной версии буста, но на моей памяти примерно достаточно, чтобы в очереди был другой таймер короче, например) и переводе системных часов назад - например, на 1 сутки, можно ждать не 30 секунд, а 1 сутки и 30 секунд
аналогично при переводе вперед - можно сломать "хорошие" соединения, посчитав их истекшими
вряд-ли кого то это сильно коснется, но я не мог это не рассказать, т.к. это когда-то решал)
Так а в asio других таймеров вроде бы и нет?
http://pastebin.com/mmQ9VWje
я помню свою радость, когда в буст добавили chrono, хоть и простая, но очень полезная либа
Листать же потом неудобно эти портянки. А спойлеров тут нет. Потому и внешний линк.
Для говнокода это не проблема. Народ, навались, создай спойлер в комментах с кодом, заминусовав!
Я все жду когда в бууст добавят unique_ptr наконец
http://www.boost.org/doc/libs/1_53_0/doc/html/move.html
собсно, думаю, в этом году все подтянутся к нужной мне планке
не всегда код написан так, что вызов метода on_my_timer у мертвого объекта это переварит (да и это само по себе ub, как было написано автором)
но обычно, если лень/медленно возиться с shared_from_this(), все на это забивают, главное выйти по ошибке до того, как полезешь в свои члены
Вот и остается два варианта:
1) Не заморачиваться с shared_from_this и насильно удалять сессию вместе со всеми ее кишками, забив на UB, как я и показал в топике. Если в колбеках не забывать обрабатывать ошибки - все корректно деинициализируется, но на душе остается неприятный осадок.
2) Заморочиться с shared_from_this, а для кошерного завершения сессии вызывать cleanup(), который вызовет у подобъектов cleanup() который вызовет... Ну, в общем, куча бойлерплейта отменяющего таймеры да подчищающего shared_ptr'ы.
Может я упускаю какое-то более изящное решение?
Вот почему нет weak_from_this? :/
C shared_from_this получить shared_ptr, а потом с него получить weak_ptr
Я вот тоже подумывал написать нечто подобное, только я собираюсь в рамках С++03 и boost.
если пользоваться п.1, необходимо еще учитывать редкий момент, когда ровно в момент запуска коллбека (как тут - честный таймаут), во втором потоке у объекта вызывается деструктор - и ты такой гейзенбаг будешь сто лет искать
Ну сокет и сессии разруливаются в одном потоке, а другие потоки к ним напрямую никогда не лезут. Так что особых проблем не должно возникнуть.
> weak
Вот насчет weak_ptr надо подумать, может не так он и мешается, раз уже двое мне его советуют ;)
в эту очередь встанет коллбек на on_timer(error_code()), и пусть ты при этом "однопоточно" деструктишь сессию, коллбек тебе придет именно так, как он был запощен
спасет только io_service.stop, что не есть решение
OMG... дочитал документацию по cancel() до конца, и понял в чем ужас ситуации: These handlers can no longer be cancelled, and therefore are passed an error code that indicates the successful completion of the wait operation.
Т.е. я так понимаю адекватно отменить таймер невозможно?
It unusable at asynchronous programming. Inconvenient as ass.
UB - КРЕСТОСТАНДАРТЕН