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

c multithreading file stdio fflush

1768 просмотра

5 ответа

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

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

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

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

Автор: Serge Rogatch Источник Размещён: 08.11.2019 11:15

Ответы (5)


39 плюса

Решение

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

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


1 Согласно действующему стандарту C11.

2 (Цитируется из: ИСО / МЭК 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 вызывает любые неписанные данные для этого потока быть доставленным в среду хоста для записи в файл; в противном случае поведение не определено.

Автор: 2501 Размещён: 20.08.2016 01:48

12 плюса

В POSIX.1 и С-функции языка , которые работают на символьные потоки (представленные указателей на объекты типа FILE) являются требуются от POSIX.1c должны быть реализованы таким образом , что достигается Реентерабельность (ИСО / МЭК 9945: 1- 1996, §8.2).

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

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

Автор: geocar Размещён: 20.08.2016 01:56

9 плюса

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

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

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

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

Автор: chqrlie Размещён: 20.08.2016 12:37

1 плюс

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

Автор: Constantine Georgiou Размещён: 20.08.2016 11:58

0 плюса

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

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

Автор: Mark Hurd Размещён: 24.08.2016 05:03
32x32