Страницы руководства по чтению / записи ничего не упоминали об их безопасности потоков

По этой ссылке! Я понял, что эти функции потокобезопасны, но в этом комментарии нет ссылки на официальный документ.

С другой стороны, по этой ссылке! который говорит:

The read() function shall attempt to read nbyte bytes
from the file associated with the open file descriptor,
fildes, into the buffer pointed to by buf.
The behavior of multiple concurrent reads on the same pipe, FIFO, or 
terminal device is unspecified.

Я пришел к выводу, что функция чтения не является потокобезопасной.

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

Я протестировал эти функции с конвейером, но проблем не было (конечно, я знаю, что не смог бы сформулировать какой-либо определенный результат, протестировав какой-то пример)

Заранее спасибо:)

1
milad 2 Май 2019 в 20:32

3 ответа

Лучший ответ

Потоково-безопасными версиями read и write являются pread и pwrite:

pread ( 2 )

   The pread() and pwrite() system calls are especially useful in
   multithreaded applications.  They allow multiple threads to perform
   I/O on the same file descriptor without being affected by changes to
   the file offset by other threads.

Когда два потока пишут () одновременно, порядок не указан (какой вызов записи завершается первым), поэтому поведение не определено (без синхронизации)

2
NTDLS 2 Май 2019 в 20:24

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

В документации POSIX read (обратите внимание на выделенные жирным шрифтом части ) :

Функция read() должна попытаться прочитать nbyte байт из файла, связанного с дескриптором открытого файла fildes, в буфер, указанный buf. Поведение нескольких одновременных чтений на одном канале, FIFO или терминальном устройстве не определено .

Это та часть, которую вы заметили, но она не охватывает все возможные типы файловых дескрипторов, таких как обычные файлы. Это относится только к «pipe [s], FIFO [s]» и «оконечному устройству [s]». Эта часть охватывает почти все остальное (странные вещи, такие как «файлы» в /proc, которые генерируются ядром на лету, ну, в общем, странные и сильно зависящие от реализации):

Для файлов, которые поддерживают поиск (например, обычный файл), read() должен начинаться с позиции в файле, заданной смещением файла, связанным с fildes . Смещение файла должно увеличиваться на количество фактически прочитанных байтов.

Поскольку «смещение файла, связанного с fildes», может быть изменено другими потоками в процессе, следующий код не гарантирует возвращение тех же результатов, даже если содержимое файла и входные данные для fd совпадают , offset, buffer и bytes:

lseek( fd, offset, SEEK_SET );
read( fd, buffer, bytes );

Поскольку оба read() и write() зависят от состояния (смещение текущего файла), которое может быть изменено в любой момент другим потоком, они не являются безопасными для протектора.

1
Andrew Henle 2 Май 2019 в 18:34

В некоторых встроенных файловых системах или действительно старых настольных системах, не предназначенных для поддержки поддержки многозадачности (например, MS-DOS 3.0), попытка выполнить fread() для одного файла в то время, как выполняется fread() выполнение другого файла может привести к произвольному повреждению системы.

Любая современная операционная система и языковая среда выполнения гарантируют, что такое повреждение не произойдет в результате операций, выполняемых над несвязанными файлами, или когда независимые файловые дескрипторы используются для доступа к одному и тому же файлу способами, которые не изменяют его. Такие функции, как fread() и fwrite(), будут потокобезопасными при использовании таким способом .

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

0
supercat 2 Май 2019 в 20:45