2012-03-13 2 views
0

Проект: типичная чат-программа. Сервер должен получать текст от нескольких клиентов и вентилировать каждый вход для всех клиентов.Это подходящее использование для shared_ptr?

На сервере я хочу, чтобы каждый клиент имел структуру, содержащую сокет fd и std :: queue. Каждая структура будет в std :: list.

Как вход получен из сокета клиента Я хочу перебрать список структур и поместить новый ввод в каждую очередь клиентской структуры. Строка новая [ed], потому что я не хочу, чтобы копии строки умножались на всех клиентов. Но я также хочу избежать головной боли, чтобы иметь несколько указателей на строку, разложенную и решающую, когда пришло время окончательно удалить строку.

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

Спасибо за любую помощь.

+0

Да, хотя я считаю, что это не подходит для 'std :: list'. 'vector' FTW! :) –

+0

@Billy ONeal - почему вектор? Выбор списка OP лучше для чего-то, где соединения постоянно добавляются и удаляются. – Duck

+1

@ Duck: 'std :: list' имеет плохую локальность, что обычно ухудшает производительность более чем на несколько дополнительных копий. –

ответ

2

Это подходящее использование shared_ptr. И да, количество использования будет увеличиваться, потому что новый shared_ptr будет создан для нажатия.

+0

Чтобы быть ясным, если я это делаю: rawPtr = новая строка; shared_ptr (сырье); push (shared_ptr); ... является refcnt 1 или 2 в этой точке? Если 2, то он действительно удаляется после того, что все всплывает, после чего выходит из сферы действия, правильно? Pls пропустил синтаксис выше, я просто ищу концепцию. –

+0

Если вы нажмете один и тот же 'shared_ptr' более одного раза, а затем выйдете из области видимости, число будет равно числу нажатий. (Не забудьте нажать копии * той же * 'shared_ptr'.) –

4

Это случай, когда система сбора псевдо-мусора будет работать намного лучше, чем подсчет ссылок.

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

Теперь каждому соединению необходимо только отслеживать индекс последней отправленной строки. Периодически (каждое полученное 1000-е сообщение или каждый полученный 4 МБ или что-то в этом роде) вы найдете минимум этого индекса для всех клиентов и удаляете строки до этой точки. Эта периодическая проверка также позволяет обнаружить клиентов, которые значительно отстали (возможное поврежденное соединение) и восстановить. Без этой проверки один застрявший клиент заставит вашу программу утечки памяти (даже по схеме подсчета ссылок).

Эта схема в несколько раз меньше данных, чем подсчет ссылок, а также удаляет одну из основных точек конкуренции в кеше (количество ссылок должно быть записано из нескольких потоков, что приводит к потере производительности). Если вы не используете потоки, все равно будет быстрее.

+0

Интересный способ подумать об этом. Это касается предстоящей заботы о том, как обращаться с медленными клиентами. Мне придется подумать об этом. Спасибо. –

+0

И если вам нужно время от времени отправлять сообщения одному клиенту, вы можете просто оставить их в отдельной очереди. –

Смежные вопросы