sendto () пока заблокирован на select () - PullRequest
0 голосов
/ 05 мая 2020

Могу ли я вызвать sendto() из другого потока на сокете, когда основной поток заблокирован на select() для того же сокета для проверки читаемости? Определяется ли это поведение в разных системах, например linux или windows? Или мне всегда нужно делать вещи, связанные с сокетами (select() / sendto() / recvfrom()), только из одного и того же потока?

Ответы [ 3 ]

2 голосов
/ 05 мая 2020

Я использую такую ​​архитектуру в своем приложении. Я проверил несколько источников (для Linux) и не нашел ничего против.

Единственным формальным основанием, подтверждающим эту концепцию, является стандарт POSIX - он говорит, что sendto(), а также select() являются поточно-ориентированными функциями:

POSIX.1-2001 и POSIX .1-2008 требуют, чтобы все функции, указанные в стандарте, были потокобезопасными, за исключением следующих функций

(sendto и select не указаны) из https://linux.die.net/man/7/pthreads .

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

Что касается winsock, необходимо проверить документацию, насколько ее реализация соответствует стандарту POSIX. Единственное, что я обнаружил, это is winsock2 thread safe? , что частично отвечает на ваш вопрос. В Linux вы можете проверить его код с открытым исходным кодом: https://github.com/torvalds/linux/blob/master/net/socket.c https://github.com/torvalds/linux/blob/master/fs/select.c.

ОБНОВЛЕНИЕ : еще одна полезная ссылка https://groups.google.com/forum/#! Topic / comp.os. linux .networking / cLbMGRNw8EA

0 голосов
/ 05 мая 2020

Можно, но это выглядит странно.

  1. Можно.

    Оба select и sendto действуют на сокеты, а сокеты могут быть совместно используемыми потоками или даже процессами, при условии, что вы их синхронизируете, или использовать один для чтения и один для записи. Единственный риск, если вы смешиваете запись или чтение в 2 потоках, - это получить только частичные данные (другой поток получает другую часть) или произвести мусор, потому что записанные данные смешаны. Если один поток использует select для чтения, а другой использует write, send или sendto для writing, я не вижу никаких проблем

  2. Может быть, вам не следует .

    Threads и select - это два способа достижения одной и той же цели: обработка разных каналов связи в одном процессе. При многопоточности обычно выделяют по одному потоку на каждом канале, а библиотека потоков или ОС выделяют процессорное время каждому потоку, когда ему что-то нужно делать, как если бы все потоки выполнялись одновременно. Это приводит к простым программам, в которых вы кодируете по одной задаче за раз.

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

    Обычно, если вы go на select Кстати, вы должны использовать потоки только для длинных вычислений асинхронных задач, но не для задач, связанных с вводом-выводом. Вот почему я считаю ваш текущий дизайн странным.

0 голосов
/ 05 мая 2020

С моей точки зрения, при вызове sendto из другого потока проблем быть не должно.

«основной поток заблокирован на select ()»

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

...