LINUX.ORG.RU

Можно ли использовать один сокет из разных потоков?

 ,


0

1

Вопрос навеян «нестандартным» тестовым заданием, мне бы и в голову не пришло делать такое самому.

Проблема стоит так: есть подключенный сокет (1шт), есть несколько потоков-читателей и потоков-писателей, которые должны с ним работать. Количество и тех, и других произвольное.

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

Думаю над этим уже с полчаса, разумных идей пока не появилось.


да может
даже несколько процессов - а не только потоков - могут юзать один сокет

а зачем - ну например accept на один сокет из нескольких процессов/потоков произведет распределение коннектов по разным
каму из них первым достанется ацепт - тот и поймает этот коннект

а для обычного сокета - может для чего то и пригодиться
например сислог - сокет на сислога открыт один - а писать туда может любой из потоков

ae1234 ★★
()

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

У данного подхода есть подводные камни, но их можно обойти.

Sorcerer ★★★★★
()
Ответ на: комментарий от ae1234

Про accept я знаю, но там в итоге каждому потоку/процессу достается свой персональный сокет для чтения/записи.

Пример с syslog действительно подходит, спасибо. Хотя я думал, что в его сокет напрямую никто не пишет - есть же syslog(3). Его действительно кто-то использует через сокет? Можно пример чего-нибудь опенсорсного с таким сценарием?

f0e
() автор топика
Ответ на: комментарий от f0e

самый очевидный пример - сразу и не назвали :)
самый очевидный пример это stdout stdin stderr :)

а сислог кто тока как не юзает

ae1234 ★★
()
Ответ на: комментарий от Sorcerer

В сокет при этом помещаются не сами данные для работы, а указатели на данные.

То есть потоки одного процесса общаются между собой через сокет? Даже не через пайп? И все для того, чтобы не блокироваться? Оригинально... Это действительно используется в реальных проектах? Хотел бы я взглянуть на такой код.

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

f0e
() автор топика
Ответ на: комментарий от ae1234

stdout stdin stderr

Это все-таки не сокеты, и читать/писать в них одновременно не получится. Да и вообще работать с ними из разных потоков смысла мало. Для логов удобнее использовать либу, которая сама разберется, как и куда ей писать, а остальное из нескольких потоков делать обычно незачем.

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

f0e
() автор топика

Это вообще возможно, особенно на неблокирующем сокете? И самое главное - зачем это может быть нужно?

Возможно. Только если никак не синхронизировать работу одновременных читателей и одновременных писателей, будут race condition'ы.

Иногда так удобнее структурировать приложение, например. В одной нитке принимаем запросы, отправляем их обработку нитке-воркеру. В другой нитке делаем отправку запросов:

socket -> reader -> worker -> writer -> socket

dmitry_vk ★★★
()
Ответ на: комментарий от dmitry_vk

socket -> reader -> worker -> writer -> socket

Я правильно понимаю, что reader/writer при этом работает со своим персональным сокетом? Тогда я смысла в другой организации кода не вижу.

Иначе - сначала разведем кучу потоков (которые будут 99.99% времени ждать, причем все одно и тоже), затем их синхронизируем, потом отладим... Куча проблем на пустом месте.

Убедительных примеров кроме syslog и вообще логирования придумать не пока не удалось. И syslog через сеть, тем более напрямую, используют единицы, а задание было именно об этом...

f0e
() автор топика
Ответ на: комментарий от f0e

То есть потоки одного процесса общаются между собой через сокет? Даже не через пайп?

Можно и через пайп, но socketpair обладает некоторыми полезными дополнительными возможностями (например, recv() с MSG_PEEK).

И все для того, чтобы не блокироваться?

Ещё для того, чтобы очередь задач юниксвэйно ложилась в концепцию event-driven programming: потоки-читатели могут добавить сокет в свой пул дескрипторов для поллинга. Это позволяет сделать архитектуру программы сколь угодно гибкой: поток-читатель может заниматься разными вещами, а не только разгребать свою очередь задач (например, разгребать сразу несколько очередей задач или выполнять какие-то периодические задачи).

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

Я видел только идею такого подхода, а автор идеи наверняка это реализовал. Я сам тоже реализовал и планирую использовать.

И чем это лучше неблокирующейся очереди в циклическом буфере, например?

Неблокирующаяся очередь - это хорошо, но с ней есть одна проблема: каким образом поток узнает о появлении задач в этой очереди, если их не было ранее?

Хуже как минимум наличием тяжелых системных вызовов

Если говорить о скорости, то тут как обычно всё относительно. Обработка задач скорее всего приведёт ко значительному числу системных вызовов, по сравнению с которыми один read() - капля в море. Про write() и говорить нечего: сколько и каких задач вы планируете выполнять за секунду, что опасаетесь падения производительности?

и (де)сериализацией указателей

Указатели не надо как-то дополнительно (де)сериализовывать кроме read()/write(). Так что в этом пункте отличий от других алгоритмов нет.

Sorcerer ★★★★★
()

В целом можно, но нужно быть аккуратным при использовании всяких фреймворков. Например, QT привязывает сокет к event-loop определенного потока, и сокетом можно пользоваться только из этого потока.

vzzo ★★★
()
Ответ на: комментарий от f0e

Я правильно понимаю, что reader/writer при этом работает со своим персональным сокетом? Тогда я смысла в другой организации кода не вижу

Нет, reader и writer работают с одним сокетом.

сначала разведем кучу потоков

Тут куча потоков и не нужна - один reader, один writer, много worker'ов. В качестве плюса имеет то, что код каждого из них прост.

которые будут 99.99% времени ждать

Ничего страшного, подождут.

Например, по такому принципу работает лисповый swank-сервер (штука для взаимодействия лисп-процесса с IDE).

Единственный недостаток такого способа работы — не кроссплатформенно, так как под виндой такое не сделать.

dmitry_vk ★★★
()
Ответ на: комментарий от Sorcerer

Понятно, я думал про AF_INET сокеты, а socketpair - это тот же пайп, вид сбоку.

Ещё для того, чтобы очередь задач юниксвэйно ложилась в концепцию event-driven programming

Все же классический unix-way работает с процессами, а не с потоками. Например, однопоточный node.js вполне совмещает event-driven programming и unix-way. А unix-way применительно к потокам выглядит странно, для них более подходящие методы (и задачи) есть.

каким образом поток узнает о появлении задач в этой очереди

Очевидно же - поллингом ;) В любом случае это не хуже чем уходить в ядро при каждом вызове. И когда очередь пуста, скорость менее важна, чем если она заполнена.

Обработка задач скорее всего приведёт ко значительному числу системных вызовов

Если bottleneck не в вычислениях, зачем тогда отдельные потоки? Обычный event loop справится не хуже. Разве что нужно использовать уже готовое блокирующее API типа CORBA.

сколько и каких задач вы планируете выполнять за секунду, что опасаетесь падения производительности?

Чем больше - тем лучше. И проблема скорее в интерактивности и утилизации ядер, а не в «попугаях в секунду». Иначе, опять же, зачем городить потоки, обычного unix-way хватит.

f0e
() автор топика
Ответ на: комментарий от f0e

syslog(3) и работает через сокет, только unix-сокет. И по сети (udp) в syslog пишут разное «умное» сетевое оборудование, cisco, например.

У вас там в задании не уточняется, какой сокет подразумевается, дейтаграммный или потоковый?

mky ★★★★★
()
Ответ на: комментарий от dmitry_vk

В swank сервере, скорее всего, треды ЗЕЛЕНЫЕ, а не нативные. Неудивительно, что их плодят по любому поводу. Но это хотя бы какой-то реальный пример, попробую посмотреть его.

Итого - преимущество в том, что «код проще» в определенных редких случаях. ОК, звучит разумно.

f0e
() автор топика
Ответ на: комментарий от mky

Нет, не уточняется, лишь бы был семейства AF_INET. Хотя потери UDP-пакетов, скорее всего, сделают результат бессмысленным.

Ключевой момент - количество потоков-читателей и писателей задается раздельно. Задачи у них тривиальные - читать/писать int'ы в цикле и все. Какая реальная задача за этим стоит - понятия не имею.

f0e
() автор топика
Ответ на: комментарий от f0e

В swank сервере, скорее всего, треды ЗЕЛЕНЫЕ, а не нативные.

Нет, вполне себе нативные.

dmitry_vk ★★★
()
Ответ на: комментарий от f0e

DNS как-то работает по udp с его потерями и ipsec ключами по udp обменивается :-)

В общем, для дейтаграммного сокета (udp) вполне рабочая схема, когда много потоков (допусим по числу ядер процессора) ожидают на чтении из сокета, кто первый прочтал, тот и отвечает. Данные всё равно передаются неделимой дейтаграммой.

mky ★★★★★
()

Это вообще возможно, особенно на неблокирующем сокете?

Да. Это возможно на любом сокете.

И самое главное - зачем это может быть нужно?

Банальный мультиплексинг.

LamerOk ★★★★★
()
Ответ на: комментарий от dmitry_vk

Единственный недостаток такого способа работы — не кроссплатформенно, так как под виндой такое не сделать.

Вопиющее 4.2

LamerOk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.