Разместить много wsasend на одном сокете из нескольких потоков
(вопрос скопирован с форума msdn)
MSDN говорит это:
Если вы используете порты завершения ввода / вывода, помните, что порядок вызовов, выполняемых в WSASend, также является порядком заполнения буферов. WSASend не должен вызываться на одном и том же сокете одновременно из разных потоков, поскольку это может привести к непредсказуемому порядку буфера.
Хорошо... но если я не забочусь об этом заказе, а также не забочусь о заказе, я получу его на другой стороне... могу ли я использовать его тогда? Безопасно ли вызывать WSASend из нескольких потоков? И будут ли доставлены посылки так, как я их передаю (может быть, заказано по-другому, но в комплекте)??
Например -> я отправляю [12a], [34b], [11c] и [223d] ... ([] помечает единицу, которую я передаю в WSASend за один вызов), получу ли я тогда, например, 34b, 11c, 12a, 223d? Или это может разбиться? Или я могу получить такие вещи, как 2a, 34b, 7a, 5c, ...
так что, возможно, вопрос должен быть -> это потокобезопасно? и это атомно? (Я говорю о WSASend, используемом с IOCP, поэтому перевернут)
1 ответ
Кажется, что на самом деле вызовы WSASend() не являются потокобезопасными, и что если вы намереваетесь вызывать WSASend() из нескольких потоков одного и того же соединения, то вам следует синхронизировать, чтобы только один поток фактически вызывал API в любой заданной точке (т.е. удерживать блокировку для каждого соединения вокруг вызова WSASend(). См. Этот вопрос и прилагаемый тестовый код для получения подробной информации: TCP / IP IOCP получал данные, иногда поврежденные - Visual C++ для Windows и эту запись в блоге для более подробного объяснения.
Также обратите внимание, что если вы отправляете отдельные сообщения уровня приложения, используя несколько вызовов WSASend() из нескольких потоков, у вас возникает проблема, поскольку эти несколько вызовов могут смешиваться до того, как данные будут записаны в поток TCP.
Так,
Если у вас есть 5 потоков, отправляющих "завершенные 2-байтовые сообщения", которые вы отправляете
AA, BB, CC, DD, EE и т. Д. Из 5 разных потоков, тогда вы не получите поток, содержащий
ABCCDDBAEE
но вы можете получить любую комбинацию порядка сообщений.
Если ваши потоки отправляют сообщения с несколькими отправленными вызовами, например, с тремя отправками, A1 A2 A3 из потока 1 формирует одно сообщение уровня приложения. Тогда все ставки сняты, как вы могли в конечном итоге
A1B1A2A3B2B3 и т. Д. В потоке TCP.
Если вам нужно сделать позже, вам понадобится какая-то блокировка вокруг ВСЕХ вызовов WSASend, чтобы вы могли сгруппировать несколько отправок в одну атомарную отправку уровня приложения или вам нужно использовать несколько WSABUF для одного вызова WSASend для сбора. вместе несколько записей в один вызов.