безопасно ли использовать функцию записи в GNU C с использованием нескольких потоков

записывать вызовы функций из нескольких потоков в один и тот же сокет

это безопасно ? Хотели ли мы добавить между ними синхронизацию? Будет ли это вызывать такие проблемы, как отложенная запись / чтение приложения с сетевого уровня на уровень приложения

Мы используем библиотеки GNU C ++ GCC 4 в среде Linux Redhat.

Это процесс на стороне сервера, при котором между сервером и клиентом имеется только 1 сокет, а клиент находится на двух разных машинах. Данные отправляются с сервера на клиент.

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

Проблема 2 - когда клиент отправляет данные на сервер. Данные, отправленные клиентом, отображаются в TCPdump сервера, который не получен для серверного приложения, которое выполняет чтение из сокета из одного потока с использованием функций «чтения» и «выбора» в цикле.

Нам не удалось определить схему возникновения этих проблем. Мы думаем, что это произошло, когда в один и тот же сокет записывается так много потоков. Мы не выполняем синхронизируемую функцию записи, надеясь, что ОС обрабатывает синхронизацию.


person samira    schedule 30.06.2012    source источник
comment
Это безопасно в том смысле, что ваша программа правильно сформирована, но результаты, которые вы видите на своем сокете, могут быть не такими, как вы ожидаете.   -  person Kerrek SB    schedule 30.06.2012
comment
@KerrekSB: странный комментарий. Любая небезопасная программа в этом смысле может быть названа безопасной, не так ли?   -  person Ned Batchelder    schedule 30.06.2012
comment
@NedBatchelder: Конечно, нет. Например, функция, которая зависит от статического буфера для своего внутреннего сохранения состояния, просто не потокобезопасна, а программа, которая вызывает ее несколько раз одновременно, просто плохо определена. Напротив, программа, которая одновременно вызывает write, не определяется автоматически.   -  person Kerrek SB    schedule 02.07.2012
comment
возможный дубликат гарантий параллелизма отправки через сокет   -  person selbie    schedule 02.07.2012
comment
возможный дубликат Параллельные вызовы send / recv на том же сокете действительны?   -  person Chris Dodd    schedule 12.01.2014


Ответы (3)


write () - это системный вызов, а не библиотечная функция, а системные вызовы обычно атомарны.

person user207421    schedule 03.07.2012
comment
Это правда, а не правда. Системный вызов гарантированно будет атомарным (и безопасным в том смысле, что он не приведет к сбою или повреждению ваших данных), но нет гарантии, что данные, одновременно отправленные (атомарно) двумя потоками, будут переданы атомарно: интересное чтение. Также обратите внимание, что write и send технически разрешено писать меньше, чем вы просите, и в этом случае вы должны продолжить вторую операцию записи, в любом случае теряя всю атомарность. - person Damon; 03.07.2012

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

person Ned Batchelder    schedule 30.06.2012
comment
@samira: это определенно может вызвать описанные вами проблемы, но невозможно сказать, является ли причиной синхронизация. - person Ned Batchelder; 30.06.2012
comment
при доступе к функции u может использовать мьютекс, чтобы к функции одновременно обращался только один поток ... - person shofee; 30.06.2012
comment
отсутствие мьютекса вызовет проблемы с чтением? Иногда записанные данные были видны на tcpdump через 6 минут. - person samira; 30.06.2012
comment
Я не думаю, что это правильно. write () - это системный вызов, а не библиотечная функция, а системные вызовы обычно атомарны. Я никогда не видел, чтобы где-либо говорилось, что write () не является атомарным. - person user207421; 30.06.2012
comment
@EJP: вы должны написать это как еще один ответ. - person Ned Batchelder; 30.06.2012

Было бы не указано, какой write вызов завершится первым. Переключение контекста может остановить любую из двух операций записи по первой инструкции. Это может привести к произвольному заказу. Ни write, ни ядро ​​ничего не могут с этим поделать. Это фундаментальная проблема.

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

person usr    schedule 12.01.2014