C чтение и безопасность потоков (linux)

Что произойдет, если вы вызовете read (или write или оба) в двух разных потоках в одном и том же дескрипторе файла (позволяет сказать, что нас интересует локальный файл и его дескриптор файла сокета), не используя явно механизм синхронизации?

Чтение и запись - это syscall, поэтому на одном ядре процессора, вероятно, не повезло, что два чтения будут выполняться "одновременно". Но с несколькими ядрами...

Что будет делать ядро ​​linux?

И пусть будет немного более общим: поведение всегда одно и то же для других ядер (например, BSD)?

Изменить: согласно закрыть документацию, мы должны быть уверены, что файловый дескриптор не используется syscall в другом потоке. Таким образом, это будет означать, что явная синхронизация потребуется до закрытия дескриптора файла (и, следовательно, также вокруг чтения/записи, если поток, который может вызвать его, все еще работает).

Ответ 1

Любой доступ к файловому дескриптору на системном уровне (syscall) является потокобезопасным во всех основных UNIX-подобных операционных системах. Хотя в зависимости от возраста они не обязательно являются безопасными для сигнала.

Если вы вызываете read, write, accept или подобное в файловом дескрипторе из двух разных задач, тогда механизм внутренней блокировки ядра разрешит конфликт.

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

Библиотека библиотеки stdio fread, fwrite и co. также имеют встроенную блокировку по умолчанию в структурах управления, хотя с помощью флагов можно отключить это.

Ответ 2

Комментарий о закрытии - это потому, что закрыть дескриптор файла в любой ситуации, когда какой-либо другой поток может попытаться использовать его, не имеет большого смысла. Таким образом, хотя это "безопасно" в отношении ядра, это может привести к нечетному, трудно диагностировать угловые случаи.

Если поток закрывает дескриптор файла, а второй поток пытается его прочитать, второй поток может получить неожиданную ошибку EBADF. Хуже того, если третий поток одновременно открывает новый файл, который может перераспределять один и тот же fd, а второй поток может случайно прочитать из нового файла, а не тот, который он ожидал...

Ответ 3

Позаботьтесь о тех, кто следит за вами.

Совершенно нормально защищать дескриптор файла с помощью семафора mutex. Он устраняет любую зависимость от поведения ядра, поэтому ваши границы сообщений теперь являются определенными. Затем вам не нужно ссылаться на последний абзац в нижней части строки в 15 489 строк, которая объясняет, почему мьютекс не нужен (я преувеличиваю, но вы понимаете мой смысл)

Это также дает понять всем, кто читает ваш код, что дескриптор файла используется более чем одним потоком.

Преимущество Fringe

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

Ответ 4

Результат будет зависеть от того, как потоки планируются в определенный момент времени.

Один из способов потенциально избежать поведения undefined при многопоточности - предположить, что вы выполняете операции с памятью. Например. обновление связанного списка или изменение переменной и т.д.

Если вы используете мьютексы/семафоры/блокировку или какой-либо другой механизм синхронизации, он должен работать по назначению.