Подтвердить что ты не робот

Может ли программа fflush() на одном и том же FILE * одновременно?

Может ли что-нибудь плохое (например, поведение undefined, повреждение файла и т.д.), если несколько потоков одновременно вызывают fflush() в той же переменной FILE*?

Разъяснение: Я не хочу писать файл одновременно. Я имею в виду только промывку его одновременно.

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

Хотя может случиться, что один поток записывает файл (внутри критического раздела), в то время как другой поток стирает файл (вне критического раздела).

4b9b3361

Ответ 1

Потоки в C 1 являются потокобезопасными 2. Для доступа к ней необходимы функции блокировки потока 3.

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


1 В соответствии с текущим стандартом, который является C11.

2 (Цитируется по: ISO/IEC 9899: 201x 7.21.3 Потоки 7)
Каждый поток имеет связанную блокировку, которая используется для предотвращения сбоев данных, когда несколько потоки выполнения доступа к потоку и ограничение чередования потоков выполняется несколькими потоками. Только один поток может удерживать эту блокировку одновременно. Блокировка реентерабельный: один поток может удерживать блокировку несколько раз в заданное время.

3 (Цитируется по: ISO/IEC 9899: 201x 7.21.3 Потоки 8)
Все функции, которые читают, записывают, позиционируют или запрашивают позицию потока, блокируют поток перед доступом к нему. Они освобождают блокировку, связанную с потоком, когда доступ полный. реентерабельный: один поток может удерживать блокировку несколько раз в заданное время.

4 (Цитируется по: ISO/IEC 9899: 201x 7.21.5.2 Функция fflush 2)
Если поток указывает на выходной поток или поток обновления, в котором самые последние операция не была введена, функция fflush вызывает любые неписанные данные для этого потока для доставки в среду хоста, которая должна быть записана в файл; в противном случае поведение undefined.

Ответ 2

Функции POSIX.1 и C-языка, которые работают с символьными потоками (представленными указателями на объекты типа FILE), требуются, чтобы POSIX.1c был реализован таким образом, чтобы было выполнено повторное подключение (см. ISO/IEC 9945: 1-1996, §8.2).

Это требование имеет недостаток; он налагает существенные штрафные санкции из-за синхронизации, которая должна быть встроена в реализации функций ради реентерации. POSIX.1c рассматривает этот компромисс между реинтеграцией (безопасностью) и производительностью за счет внедрения высокопроизводительных, но не реентерабельных (потенциально опасных) версий следующих стандартных функций ввода-вывода C-языка: getc(), getchar(), putc() и putchar(). Не-реентерабельные версии называются getc_unlocked() и т.д., Чтобы подчеркнуть их неясность.

Обратите внимание, однако, как отмечали другие: многие популярные системы (включая Windows и Android) не совместимы с POSIX.

Ответ 3

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

Если поток открыт в режиме обновления ("w+" или "r+"), последняя операция не должна читаться при вызове fflush(). Поскольку поток используется в различных потоках асинхронно, было бы трудно обеспечить это без какой-либо связи между процессами и синхронизации или блокировки, если вы читаете какие-либо чтения. До сих пор существует веская причина открыть файл в режиме обновления, но не зачитывайте его после запуска потока fflush.

fflush() не изменяет текущую позицию. Это просто приводит к тому, что любой буферный вывод записывается в систему. Потоки обычно защищены блокировкой, поэтому вызов fflush() в одном потоке не должен испортить вывод, выполняемый другим потоком, но он может изменить время записи системы. Если несколько потоков выводят тот же самый FILE*, порядок, в котором происходит чередование, в любом случае неопределенен. Кроме того, если вы используете fseek() разные потоки для одного и того же потока, вы должны использовать собственную блокировку для обеспечения согласованности между fseek() и следующим выходом.

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

Ответ 4

Довольно простой ответ, вы не можете этого сделать, поскольку файл имеет одну "текущую позицию". Как вы его отслеживаете? Открыт ли файл для последовательного доступа или случайного? В последнем случае вы можете открывать его несколько раз (по одному для каждого потока) и при этом разрабатывать способы согласования структуры файла.

Ответ 5

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

Таким образом, я бы работал с моделью виртуальной машины, с которой вы кодируете, и помещаем fflush() в критический раздел тоже.