2009-01-08 2 views
13

Много играл с Boost.Asio в последнее время. Мне очень нравится библиотека, так как она предлагает фантастический способ сжать производительность из сегодняшних многоядерных систем.Каков наилучший способ обеспечения действительной продолжительности жизни объекта при использовании Boost.Asio?

Вопрос, который я задал себе несколько раз, и я подумал о том, что стоит выбрасывать там время жизни объекта/владельца при совершении асинхронных вызовов с помощью Asio.

Проблема, с которой я столкнулся неоднократно, заключается в том, что вам довольно часто приходится «истекать» с объектом, у которого все еще есть асинхронные обратные вызовы. Если этот объект выходит за пределы области действия до того, как обратный вызов будет вызван, все неизбежно начнется.

Для борьбы с этим я использовал шаблон boost::enable_shared_from_this в качестве базового класса для большинства классов на основе asio. Это работает нормально, но это немного обременительно: обычно это также означает защиту конструктора и добавление фабричного метода в класс, чтобы гарантировать, что все экземпляры создаются внутри shared_ptr.

Я просто хотел узнать, как другие люди справились с этой проблемой. Я иду об этом лучше всего? Или я получил свой Asio.Foo все неправильно?

Обсудить ... :)

ответ

1

Такого рода вещи не ограничивается Asio. Недавно я написал класс потока-пула (используя Boost :: Thread), который имел почти такую ​​же проблему - потоки вызывали бы класс пула потоков, который их создавал, чтобы увидеть, какую задачу они должны были выполнить дальше, используя простой указатель к нему, и если класс потока пула был уничтожен с дочерним потоком, все еще запущенным, программа потерпит крах. Я справился с этим, вызвав interrupt по каждому из потоков деструктора пула потоков, а затем ожидая, пока все они выйдут, прежде чем вернуть деструктор.

Если я понимаю ваше решение с общим указателем, оно, похоже, выполняет ту же самую общую вещь, гарантируя, что элемент нельзя уничтожить, пока он больше не понадобится. Эстетически приятное решение тоже. Я не вижу лучшего ответа на эту проблему.

+0

Интересно, что вы упомянули этот сценарий: мой коллега (известный здесь как Алан) делал то же самое, что и вы, и я упомянул о «решении», которое я нашел, потому что для меня это была та же проблема. Я все еще не доволен этим: мне не нравится отсутствие детерминизма, но потом это топик для ya – jkp

2

Использование boost::enable_shared_from_this в значительной степени способ сделать это. Кроме того, посмотрите на использование boost::weak_ptr, если вам нужны ссылки на объект, который не должен сохранять объект, если они являются единственными ссылками, которые остаются.

Хороший пример использования weak_ptr: Я использую enable_shared_from_this в классе сокетов, который использует boost::asio. Рамка boost::asio - единственное, что хранит постоянные ссылки на объект, с помощью обработчиков чтения и записи. Таким образом, когда вызывается деструктор сокета, я знаю, что сокет закрыт, и я могу «делать вещи» в обработчике, чтобы очистить этот закрытый сокет. Приложение, которое использует сокет, имеет только ссылку weak_ptr, которое оно продвигает до shared_ptr, когда оно хочет работать с сокетом (обычно для его записи). Это продвижение может быть проверено на предмет сбоя в случае, если сокет ушел, хотя тесный обработчик сокета обычно очищает все ссылки weak_ptr, прежде чем это произойдет.