подскажите пожалуйста, если а асинхронном режиме (или в синхронном но 2 потока) пишут данные в один и тот же сокет, будет ли по порядку отправлено или же смешается в одну кучу, другими есть ли синхронизация на уровни ядра?
Re: wsasend синхронизация
От:
Аноним
Дата:
03.04.12 14:33
Оценка:
Здравствуйте, bolt7, Вы писали:
B>подскажите пожалуйста, если а асинхронном режиме (или в синхронном но 2 потока) пишут данные в один и тот же сокет, будет ли по порядку отправлено или же смешается в одну кучу, другими есть ли синхронизация на уровни ядра?
Блоки будут перемешаны естественно. Возникает вопрос — зачем два потока? Не могу придумать, зачем это могло бы понадобится?
я делаю одну библиотеку для обмена сообщениями и юзер может свободно два раза подряд отправить одному и тому же получателю разные сообщения. делаю на iocp. неужели придется синхронизировать евентами? использовать блокирующие сокеты не хочу, так как если отправляется двум разным получателям будет дольше.
Здравствуйте, bolt7.
B>я делаю одну библиотеку для обмена сообщениями и юзер может свободно два раза подряд отправить одному и тому же получателю разные сообщения. делаю на iocp. неужели придется синхронизировать евентами? использовать блокирующие сокеты не хочу, так как если отправляется двум разным получателям будет дольше.
Когда-то тоже начинал писать на raw IOCP. И тоже столкнулся с подобным вопросом (у меня были одновременная отправка и получение). Потом перешел на Boost.Asio. Там проблема решена так. Мне это решение очень понравилось и, наряду с таймерами, повернуло мой проект в сторону Asio.
Programs must be written for people to read, and only incidentally for machines to execute
а разве для приема и отправки не два разных буфера? у меня проект на си, так что никаких классов. да и тем более у меня должна выйти легкая и быстрая библиотечка, и использовать библиотеки классов рассчитаны на все случаи жизни, тут будет неоправданная роскошь. будем думать...
B>а разве для приема и отправки не два разных буфера?
Проблема не в буферах, а в общих для обеих операций (и не только для них — есть еще таймеры и внешнее управление) per-socket-data. В основном, это флаги состояний сессии: идет ли операция чтения, идет ли операция записи, получен ли сигнал к завершению работы или прочие сигналы внешнего управления. Не вводить же mutex на каждую сессию — он может заблокировать более одного рабочего потока из пула, обслуживающего IOCP, в случае, когда до окончания обработки одного completion packet придет следующий completion packet, относящийся к тому же сокету. В подобной ситуации работать будет только один рабочий поток — остальные будут просто ждать в то время, как на обслуживаемом ими IOCP могут быть другие готовые completion packet, относящиеся к другим сокетам и, следовательно, позволяющие обработать их параллельно.
И еще — я не нашел в MSDN информации, подтверждающей допустимость одновременного использования одного и того же сокета из разных потоков. Может кто подскажет?
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, bolt7, Вы писали:
B>а как быть если не знаешь заранее размер посланных данных? посылать сначала длину, а потом сами данные; или как то по изящнее можно?
Как это не знаешь размер посланных? Так да, стандартно, придумываешь протокол — 2 (4) байта длина, потом данные. Часто делается заголовок — длина, команда, опции и потом данные (или без данных).
Здравствуйте, abrarov, Вы писали:
A>Проблема не в буферах, а в общих для обеих операций (и не только для них — есть еще таймеры и внешнее управление) per-socket-data.
Не вижу проблемы. Может, неудачное проектирование?
A>И еще — я не нашел в MSDN информации, подтверждающей допустимость одновременного использования одного и того же сокета из разных потоков. Может кто подскажет?
А почему нет то? Сокет дуплексный, к потокам не привязан.
в смысле мне посланных)и это придется в два захода считывать — размер, потом выделить буфера и сами данные. меня только волнует если опять таки одновременно будут слать по одному сокету несколько потоков на принимающей стороне я не разберусь что к чему. нормально будет сделать на каждое соединению по одному евенту/мутексу и пока один не закончит передачу, второй ждет на этом объекте? не будет ли перевод в спячку и обратно слишком затратной операцией? (будет дольше проворачивать все это дело, чем слать данные)
Здравствуйте, bolt7, Вы писали:
B>в смысле мне посланных)и это придется в два захода считывать — размер, потом выделить буфера и сами данные.
Ну ты что, 2 байта считывать будешь? Читаешь то в размер буфера. Принял всё, и потом разбираешь.
B>меня только волнует если опять таки одновременно будут слать по одному сокету несколько потоков на принимающей стороне я не разберусь что к чему.
Кто тебе будет слать? Давай сферическое не обсуждать. Придумал конкретную схему обмена, конкретный протокол, и реализовываешь.
B>нормально будет сделать на каждое соединению по одному евенту/мутексу и пока один не закончит передачу, второй ждет на этом объекте?
Послали, получили уведомление о завершении, послали ещё порцию. Не надо мудрить.
B>в смысле мне посланных)и это придется в два захода считывать — размер, потом выделить буфера и сами данные.
Читать можно и больше, чем только заголовок — по завершении операции чтения парсим все, что прочиталось. Где-то я уже видел обсуждение этого. Кажется, на vingrad-е.
B>меня только волнует если опять таки одновременно будут слать по одному сокету несколько потоков на принимающей стороне я не разберусь что к чему.
Если речь идет о TCP, то это потоковый протокол и разделение сообщений должно быть реализовано приложением. Накапавливаем исходящие сообщения в собственном буфере (в очереди) и отсылаем их по мере возможности (после успешного завершения очередной операции отправки).
B>нормально будет сделать на каждое соединению по одному евенту/мутексу и пока один не закончит передачу, второй ждет на этом объекте? не будет ли перевод в спячку и обратно слишком затратной операцией? (будет дольше проворачивать все это дело, чем слать данные)
A>>Проблема не в буферах, а в общих для обеих операций (и не только для них — есть еще таймеры и внешнее управление) per-socket-data.
G>Не вижу проблемы. Может, неудачное проектирование?
читали остальную часть моего сообщения или хотя бы Network Programming for Microsoft Windows?
A>>И еще — я не нашел в MSDN информации, подтверждающей допустимость одновременного использования одного и того же сокета из разных потоков. Может кто подскажет?
G>А почему нет то? Сокет дуплексный, к потокам не привязан.
То, что сокет дуплексный, не подразумевает, что один и тот же сокет можно безопасно использовать одновременно из нескольких потоков.
Programs must be written for people to read, and only incidentally for machines to execute
стоп я запутался
1. вот юзер посылает чтото _send_data(dest,size1,buf1)
потом сразу же еще чото _send_data(dest,size2,buf2)
одному и томуже dest. как я должен теперь разрулить отправку через wsasend.
2. по поводу отправки размера и самих даных если я правильно понял то это — выдиляем новый буфер size+2, пишем в первые 2 байта размер, а потом копируем то что нужно послать и отправляем. тогда вопрос, может есть функция которой передается массив буферов и она ои отправляет за один раз, а то каждый раз выдилять/освобождать память для каждой посылки не очень как то. и кстате почему 2 байта на размер, что нельзя послать за раз больше 64кб?
... лучше почитать "Programming Server-Side Applications for Microsoft Windows 2000" на тему размера пула потоков, обслуживающих IOCP, и выноса длительной работы в другой пул/потоки.
Programs must be written for people to read, and only incidentally for machines to execute
B>стоп я запутался B>1. вот юзер посылает чтото _send_data(dest,size1,buf1) B> потом сразу же еще чото _send_data(dest,size2,buf2) B> одному и томуже dest. как я должен теперь разрулить отправку через wsasend.
> Накапавливаем исходящие сообщения в собственном буфере (в очереди) и отсылаем их по мере возможности (после успешного завершения очередной операции отправки).
B>2. по поводу отправки размера и самих даных если я правильно понял то это — выдиляем новый буфер size+2, пишем в первые 2 байта размер, а потом копируем то что нужно послать и отправляем. тогда вопрос, может есть функция которой передается массив буферов и она ои отправляет за один раз, а то каждый раз выдилять/освобождать память для каждой посылки не очень как то. и кстате почему 2 байта на размер, что нельзя послать за раз больше 64кб?
Вот алгоритм для чтения. Для записи будет похожий — тут уж лучше Вам самому подумать.
"Выделять буферы" вообще лишнее — используем один буфер и serializator + очередь ref-counted сообщений.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали:
A> :) читали остальную часть моего сообщения
Читал. Проблемы не увидел, честно. Может проблема проявляется где-то, с чем-то я не сталкивался. Вот пишу я PortMapper (прокси), там на сокете одновременно передача и приём. Проблем нет.
A>или хотя бы Network Programming for Microsoft Windows?
Читал. Где конкретно там описаны трудности?
A>То, что сокет дуплексный, не подразумевает, что один и тот же сокет можно безопасно использовать одновременно из нескольких потоков.
Здравствуйте, abrarov, Вы писали:
A>... лучше почитать "Programming Server-Side Applications for Microsoft Windows 2000" на тему размера пула потоков, обслуживающих IOCP, и выноса длительной работы в другой пул/потоки.
Здравствуйте, bolt7, Вы писали:
B> одному и томуже dest. как я должен теперь разрулить отправку через wsasend.
wsasend
завершение
wsasend
завершение
wsasend
завершение
...
B>по поводу отправки размера и самих даных если я правильно понял то это — выдиляем новый буфер size+2
Есть постоянный буфер на подключение — например, 8Кб. В первые 2 байта пишешь размер, потом добиваешь данными, отправляешь сколько надо.
B>и кстате почему 2 байта на размер, что нельзя послать за раз больше 64кб?
Да хоть 8 байт сделай, твой протокол. Понятно, большие данные шлёшь кусками, размером с буфер.
G>Читал. Проблемы не увидел, честно. Может проблема проявляется где-то, с чем-то я не сталкивался. Вот пишу я PortMapper (прокси), там на сокете одновременно передача и приём. Проблем нет.
Используем пул потоков (T1, T2), обслуживающих один IOCP и несколько сокетов (сервер, клиент с несколькими сокетами) — A, B, C, D.
Предположим, per-socket-data (в т.ч. сам сокет), Вы защищаете mutex-ом (по одному на каждый сокет).
Предположим, до окончания обработки рабочим потоком T1 одного completion packet, относящегося к сокету A, придет следующий completion packet, относящийся к тому же сокету A.
В этой ситуации из пула поднимается рабочий поток T2 и пытается обработать completion packet сокета A.
T2 застревает на mutex сокета A, так как T1 еще не закончил обработку.
В тоже время в IOCP имеется еще несколько готовых completion packets для сокетов B, C, D, которые могли бы быть обработаны потоком T2, пока T1 не закончил с сокетом A.
G>Теряюсь. Какая разница какой поток пишет/читает?
Дуплексный != thread-safe.
Programs must be written for people to read, and only incidentally for machines to execute
A>>... лучше почитать "Programming Server-Side Applications for Microsoft Windows 2000" на тему размера пула потоков, обслуживающих IOCP, и выноса длительной работы в другой пул/потоки.
G>Это топикстартеру?
Да. Здесь нельзя редактировать сообщения — приходится изощряться.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали: A>"Выделять буферы" вообще лишнее — используем один буфер и serializator + очередь ref-counted сообщений.
как — то страшно звучит, 2 сенда не быстрее уже тогда сделать и надеятся что алгоритм нагла успеет сработать, и отправится как за один сенд
B>как — то страшно звучит, 2 сенда не быстрее уже тогда сделать и надеятся что алгоритм нагла успеет сработать, и отправится как за один сенд
Не нашел в MSDN (хотя где-то здесь писали, что по факту это так) упоминания о том, что асинхронная отправка завершается (приходит completion packet), только тогда, когда все данные, на которые указывает буфер, отправлены (а не когда отправлено хоть что-то из того, что было указано в WSASend). Подумайте, что будет, со вторым send, вызванным еще до завершения предыдущего. Зачем-то же GetQueuedCompletionStatus возвращает через lpNumberOfBytes кол-во отправленных/полученных байт.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали:
G>>Читал. Проблемы не увидел, честно. Может проблема проявляется где-то, с чем-то я не сталкивался. Вот пишу я PortMapper (прокси), там на сокете одновременно передача и приём. Проблем нет.
A>Используем пул потоков (T1, T2), обслуживающих один IOCP и несколько сокетов (сервер, клиент с несколькими сокетами) — A, B, C, D. A>Предположим, per-socket-data (в т.ч. сам сокет), Вы защищаете mutex-ом (по одному на каждый сокет). A>Предположим, до окончания обработки рабочим потоком T1 одного completion packet, относящегося к сокету A, придет следующий completion packet, относящийся к тому же сокету A. A>В этой ситуации из пула поднимается рабочий поток T2 и пытается обработать completion packet сокета A. A>T2 застревает на mutex сокета A, так как T1 еще не закончил обработку. A>В тоже время в IOCP имеется еще несколько готовых completion packets для сокетов B, C, D, которые могли бы быть обработаны потоком T2, пока T1 не закончил с сокетом A.
Вы не правы, так делать не нужно — не нужно синхронизировать работу с сокетом mutex-ом — это все портит. Нужно использовать что-то вроде lock-free, а для того чтобы восстановить порядок буферов при вызове recv в структуре нужно указать номер операции. Но даже если делать через блокировки, то чтобы решить проблему которую вы описали в своем примере, необходимо просто сделать очередь необработанных запросов. Хотя это на мой взгляг не есть гуд, но это простое и очевидное решение, которое довольно часто используется.
G>>Теряюсь. Какая разница какой поток пишет/читает? A>Дуплексный != thread-safe.
Опять не правы... виндовые сокете потокобезопасны, тут есть другой подводный камень...
Здравствуйте, vf.
A>>Используем пул потоков (T1, T2), обслуживающих один IOCP и несколько сокетов (сервер, клиент с несколькими сокетами) — A, B, C, D. A>>Предположим, per-socket-data (в т.ч. сам сокет), Вы защищаете mutex-ом (по одному на каждый сокет). A>>Предположим, до окончания обработки рабочим потоком T1 одного completion packet, относящегося к сокету A, придет следующий completion packet, относящийся к тому же сокету A. A>>В этой ситуации из пула поднимается рабочий поток T2 и пытается обработать completion packet сокета A. A>>T2 застревает на mutex сокета A, так как T1 еще не закончил обработку. A>>В тоже время в IOCP имеется еще несколько готовых completion packets для сокетов B, C, D, которые могли бы быть обработаны потоком T2, пока T1 не закончил с сокетом A.
vf>Вы не правы, так делать не нужно — не нужно синхронизировать работу с сокетом mutex-ом — это все портит. Нужно использовать что-то вроде lock-free, а для того чтобы восстановить порядок буферов при вызове recv в структуре нужно указать номер операции. Но даже если делать через блокировки, то чтобы решить проблему которую вы описали в своем примере, необходимо просто сделать очередь необработанных запросов. Хотя это на мой взгляг не есть гуд, но это простое и очевидное решение, которое довольно часто используется.
Я как раз таки против использования мьютекса — мне нравится boost::asio::io_sevice::strand — а это и есть очередь
G>>>Теряюсь. Какая разница какой поток пишет/читает? A>>Дуплексный != thread-safe. vf>Опять не правы... виндовые сокете потокобезопасны, тут есть другой подводный камень...
Я не утверждаю, что виндовые сокеты непотокобезопасны. Я просто не нашел в MSDN явного указания на то, что они потокобезопасны — может кто даст ссылку?
А подводный камень есть в том, что (я уже писал в этом топике) в MSDN нет гарантий того, что асинхронная отправка (WSASend) успешно завершается лишь после отправки всего (а не хотя бы чего-то), что было предложено передать при вызове WSASend (может я ошибаюсь?).
К тому же с сокетом часто ассоциировано состояние сессии, поэтому, когда использется полноценная дуплексная логика (см. док-цию Boost.Asio — implicit strand & explicit strand), появляется необходимость синхронизировать доступ к этому состоянию.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали:
G>>>>Теряюсь. Какая разница какой поток пишет/читает? A>>>Дуплексный != thread-safe. vf>>Опять не правы... виндовые сокете потокобезопасны, тут есть другой подводный камень...
A>Я не утверждаю, что виндовые сокеты непотокобезопасны. Я просто не нашел в MSDN явного указания на то, что они потокобезопасны — может кто даст ссылку?
Да, в мсдн-е не находится... наверное нужно искать в книжках у мс-вских гуру. http://tangentsoft.net/wskfaq/intermediate.html#threadsafety
Там же, к конце про то что я считаю подводным камнем.
A>А подводный камень есть в том, что (я уже писал в этом топике) в MSDN нет гарантий того, что асинхронная отправка (WSASend) успешно завершается лишь после отправки всего (а не хотя бы чего-то), что было предложено передать при вызове WSASend (может я ошибаюсь?).
Думаю, что ошибаетесь. Мне такое поведение видится абсолютно абсурдным, в контексте того что допускается многократный вызов WSASend до завершения операции, потому что не оставляет никаких возможностей продолжить передачу данных.
Здравствуйте, abrarov, Вы писали:
A>А подводный камень есть в том, что (я уже писал в этом топике) в MSDN нет гарантий того, что асинхронная отправка (WSASend) успешно завершается лишь после отправки всего (а не хотя бы чего-то), что было предложено передать при вызове WSASend (может я ошибаюсь?).
Уведомление о завершении приходит, когда "освобождаются" переданные в WSASend пользовательские буферы. То есть получив уведомление об успехе, Вы вольны делать с буферами что угодно, системе их содержимое более не требуется. Но это совершенно не означает, что все данные или хотя-бы их часть уже отправлены, при ненулевых буферах сокета(SO_SNDBUF) система просто копирует Ваши данные в свой внутренний буфер и сразу извещает Вас о завершении операции.
Здравствуйте, Jolly Roger.
JR>Уведомление о завершении приходит, когда "освобождаются" переданные в WSASend пользовательские буферы. То есть получив уведомление об успехе, Вы вольны делать с буферами что угодно, системе их содержимое более не требуется. Но это совершенно не означает, что все данные или хотя-бы их часть уже отправлены, при ненулевых буферах сокета(SO_SNDBUF) система просто копирует Ваши данные в свой внутренний буфер и сразу извещает Вас о завершении операции.
... If the overlapped operation is successfully initiated and will complete later, WSASend returns SOCKET_ERROR and indicates error code WSA_IO_PENDING. In this case, lpNumberOfBytesSent is not updated. When the overlapped operation completes the amount of data transferred is indicated either through the cbTransferred parameter in the completion routine (if specified), or through the lpcbTransfer parameter in WSAGetOverlappedResult.
но
If you are using I/O completion ports, be aware that the order of calls made to WSASend is also the order in which the buffers are populated. WSASend should not be called on the same socket simultaneously from different threads, because it can result in an unpredictable buffer order.
Написать прямым текстом о том, что обсуждается в этой ветке, видимо, не позволяет религия.
Опять же, могли бы предупредить, что completion packet м/б выбран рабочим потоком из IOCP еще до выхода из WSASend/WSARecv...
Programs must be written for people to read, and only incidentally for machines to execute
а если одновременно по одному и тому же соединению с разных концов (и клиент и сервер) пишет чтото, данные не перемешаются и каждый из сторон получат то что им отправляли? или нет?
Здравствуйте, Аноним, Вы писали:
А>а если одновременно по одному и тому же соединению с разных концов (и клиент и сервер) пишет чтото, данные не перемешаются и каждый из сторон получат то что им отправляли? или нет?
Соединение полнодуплексное. Значит юзается два буфера (для каждого направления передачи).
Re: wsasend синхронизация
От:
Аноним
Дата:
07.04.12 10:19
Оценка:
здравствуйте, проясните пожалуйсто ситуацию с передачей больших данных (в несколько мегабайт). мне нужно их самому отправлять порциями или ядро само это сделает, и если да то какой размер порции должен быть чтоб маршрутизатор пропустил?