хранение и управление перекрывающейся структурой на многопоточном сервере IOCP

Это хорошая идея использовать LINKED LIST для хранения перекрывающейся структуры?

моя перекрывающаяся структура выглядит так

typedef struct _PER_IO_CONTEXT 
{

  WSAOVERLAPPED               Overlapped;
  WSABUF                      wsabuf;
  ....
  some other per operation data
  ....
  struct _PER_IO_CONTEXT      *pOverlappedForward;
  struct _PER_IO_CONTEXT      *pOverlappedBack;

 } PER_IO_CONTEXT, *PPER_IO_CONTEXT;

Когда сервер iocp запускается, я выделяю (например) 5000 из них в связанном списке. Начало этого списка хранится в глобальной переменной PPER_IO_CONTEXT OvlList. Я должен добавить, что я использую этот связанный список только в том случае, когда мне нужно отправить данные всем подключенным клиентам. Когда отправляется Wsasend или GQCS получает уведомление, связанный список обновляется (я использую EnterCriticalSection для синхронизации). Заранее спасибо за ваши советы, мнения и предложения по лучшему хранению (кешированию) перекрывающейся структуры.


person maciekm    schedule 30.12.2013    source источник
comment
Почему бы не использовать встроенную структуру данных, такую ​​как вектор или мешок/набор? Вы ограничены C?   -  person usr    schedule 30.12.2013
comment
@usr Я не ограничен C, но мои навыки программирования все еще невелики, и мне нужен совет от лучшего программиста. Вектор? Могу ли я использовать это на многопоточном сервере? что с синхронизацией?   -  person maciekm    schedule 30.12.2013
comment
Вы также должны синхронизировать доступ к своему пользовательскому связанному списку. Никакой разницы. Создавая все самостоятельно, вы усложняете себе работу, а не облегчаете ее. Попробуйте мыслить на более высоком уровне вместо создания собственных структур данных.   -  person usr    schedule 30.12.2013
comment
Я просто помещаю эти вещи в обычную потокобезопасную очередь производитель-потребитель, которая действует как пул.   -  person Martin James    schedule 30.12.2013
comment
Если бы я собирал его, я бы, вероятно, использовал deque - нужен только доступ к концам (с критическим разделом и семафором).   -  person Martin James    schedule 30.12.2013


Ответы (1)


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

Использование одного «пула» уменьшает конкуренцию между «конфликтом между всеми потоками, использующими распределитель, который используется для выделения и уничтожения перекрывающихся структур», до «конфликта между всеми потоками, выдающими или обрабатывающими операции ввода-вывода», что обычно хорошо. сделать. Вы правы, что вам нужно синхронизировать доступ, критический раздел или, возможно, блокировку SRW в эксклюзивном режиме, вероятно, лучше всего (последний немного быстрее для неоспариваемого доступа).

Уменьшения фрагментации кучи также стоит добиться в долго работающей системе.

Использование «стандартного» неинвазивного списка, такого как std::deque, поначалу выглядит очевидным выбором, но проблема с неинвазивными коллекциями заключается в том, что они имеют тенденцию выделять и освобождать память для каждой операции (так что вы вернулись к исходному соглашению) . Гораздо лучше, ИМХО, поместить указатель в каждую перекрывающуюся структуру и просто связать их вместе. Это не требует выделения или освобождения дополнительной памяти при доступе к пулу и означает, что ваше соперничество возвращается только к потокам, которые используют пул.

Лично я считаю, что мне нужен только односвязный список структур для каждой операции для пула (свободный список), который на самом деле является просто стеком, и двусвязный список, если я хочу поддерживать список «используемых» «по- данные операции, которые иногда бывают полезны (хотя это не то, чем я сейчас занимаюсь).

Следующим шагом может быть несколько пулов, но это будет зависеть от конструкции вашей системы и от того, как работает ваш ввод-вывод.

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

person Len Holgate    schedule 31.12.2013
comment
, Очень полезный ответ. Также полезно прочитать большинство ваших ответов на этом сайте, касающихся iocp, если кто-то хочет знать, как работает iocp. Большое спасибо. - person maciekm; 02.01.2014