2015-03-02 4 views
1

Я работаю над инструментом, который записывает данные в файлы.Ждите, пока файл будет доступен для записи

В какой-то момент файл может быть «заблокирован» и не доступен для записи до тех пор, пока не будут закрыты другие ручки.

Я мог бы использовать API CreateFile в цикле, пока файл не будет доступен для доступа к записи.

Но у меня есть 2 проблемы с использованием CreateFile в цикле:

  • жёсткий диск (кэш) всегда работает ...?!
  • Мне нужно позвонить CreateFile еще раз, чтобы получить действительный дескриптор с разными флагами ...?!

Так что мой вопрос:

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

Есть ли какие-либо решения для проведения мероприятий или что-то еще, что позволяет «стоять/резервировать» ручку один раз, чтобы не было «неконтролируемого» состояния гонки с другими?

+1

Жесткие диски не имеют проблем с «всегда работает», это то, что они предназначены для ... –

+0

@JonathanPotter Я не согласен. Если жесткий диск остается в одном секторе, будут задержки и отставание в производительности. Также он изнашивается. Если такие вещи обрабатываются в памяти, это совсем другая история. –

+3

Мой комментарий был немного увлекательным, я дам вам. Но вам не нужно беспокоиться. Файловая система кэшируется в памяти. Неоднократно попытка открыть дескриптор файла почти наверняка не коснется диска. –

ответ

3

Файл может быть «заблокирован» по двум причинам:

  1. Фактического файл lock , который предотвращает запись и, возможно, чтение из файла.
  2. Файл открыт без доступа (случайно или добровольно) , который даже препятствует открытию ручки. Если вы уже видите ошибку CreateFile, это скорее всего случай, а не реальный замок.

Есть концептуально [1] по крайней мере, два пути, зная, что никакой другой процесс не заблокировал файл без напряженного ожидания:

  1. Находя, кто держит замки и ждет от процесса или нить для выхода (или, по наповал убивает их ...)
  2. блокируя файл сами

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

К счастью,, удерживая замок, предполагает наличие ручки. Закрытие дескриптора файла разблокирует все диапазоны файлов. Это означает: без блокировки без ручки.

Иными словами, проблема также может быть выражена как «кто держит открытую ручку в файле?». Конечно, не все процессы, которые содержат дескриптор файла, будут заблокированы, но никакой процесс с дескриптором гарантирует, что процесс не заблокирован.
Код для определения того, какие процессы имеют открытый файл, намного проще (с использованием диспетчера перезапуска) и readily available на сайте Raymond Chen.

Теперь, когда вы знаете, какие процессы и потоки хранят файлы и блокировки файлов, создайте список всех ручек потока/процесса и используйте WaitForMultipleObjects в списке обработчиков процессов. Когда процесс завершается, все дескрипторы закрыты.
Это также прозрачно рассматривает возможность «блокировки», потому что процесс не передает доступ.

Блокировка файла самостоятельно
Вы можете использовать LockFileEx, который работает асинхронно. Обратите внимание: LockFileEx нужен действительный дескриптор, который был открыт с либо права на чтение или запись (получение разрешения на запись может быть невозможным, но чтение должно работать почти всегда - даже если вам запрещено фактически с чтением с помощью эксклюзивной блокировки , все равно можно создать дескриптор, который мог бы читать, если бы не было блокировки).

Вы можете подождать при асинхронной блокировке, чтобы завершить либо через событие в структуре OVERLAPPED, либо на порте завершения, но и даже сделать другие полезные вещи в среднее время. Как только вы заблокировали файл, вы знаете, что никто его не заблокировал.


[1] формулировка «концептуально» предполагает, что я уверен, что любой метод будет работать, но я не проверял их.

1

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

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

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

Существует вероятность того, что вы можете ждать в лучшую сторону: если файл заблокирован для записи, можно предположить, что кто-то собирается писать в него, и поэтому использовать FindFirstChangeNotification получать события для FILE_NOTIFY_CHANGE_LAST_WRITE или событий FILE_NOTIFY_CHANGE_ATTRIBUTES , Это не идеально, потому что кто-то может запросить эксклюзивный доступ для чтения.

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

+1

Я считал, что файл можно заблокировать бесконечно. Теперь меня больше беспокоит состояние «гонки» ... Это кажется немного несправедливым, если есть, например, 2 разных цикла, и 1 цикл быстрее, чем другой, и всегда «крадет» ручку, которая позволяет второму циклу никогда не получить поворот. Я думал, что будет решение «зарезервировать» дескриптор один раз и проверить это, вместо того, чтобы использовать 'CreateFile' –

Смежные вопросы