2010-04-07 2 views
3

Я работаю с двумя независимыми приложениями c/C++ в Windows, где один из них постоянно обновляет изображение на диске (с веб-камеры), а другой читает это изображение для обработки. Это работает отлично и dandy 99,99% времени, но время от времени приложение-читатель находится в середине чтения изображения, когда автор удаляет его, чтобы обновить его новым.файл блокировки, чтобы его нельзя было удалить

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

Спасибо,

-Роберт

+1

Вы должны указать целевую ОС, так как она делает * огромную * разницу. Однако я бы предложил сделать операцию атомом (подсказка: переименование и удаление часто являются атомарными для локальной файловой системы, а не как пара, но индивидуально). В зависимости от вашей ОС и различных настроек файлов они будут иметь другую семантику. – 2010-04-07 02:16:40

+0

Моя целевая ОС - Windows. – JoeCool

ответ

4

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

+1

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

+2

Создайте именованный мьютекс и который может использоваться обоими процессами. – Ramakrishna

+0

Ах, это звучит, пожалуй, лучший вариант. Я дам этот выстрел, спасибо! – JoeCool

3

Да, механизм блокировки не поможет. Есть, к сожалению, несколько на выбор. Linux/Unix, например. имеет flock (2), Windows имеет аналогичный (но другой) механизм.

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

+0

На самом деле я использую технику переименования прямо сейчас, но я не вижу, как это будет исправлено для всех случаев. Например, скажем, читатель находится на полпути через чтение файла, но автор готов его обновить (он сначала записал во временный файл и собирается переименовать его в имя файла, которое ожидает читатель). Когда он переименовывает его и таким образом уничтожает первый файл, читатель, который находится только на полпути через чтение первого файла, наверняка получит сообщение об ошибке, так как файл, который он читает, сбивается, правда? – JoeCool

+2

Не знаю о Windows, но в Unix/Linux произойдет то, что переименование приведет к отключению предыдущей версии файла, но пока читатель имеет открытый файловый дескриптор, он может продолжать читать счастливо. Трюк переименования является стандартным механизмом для обеспечения того, чтобы читатель получал либо старую, либо новую версию файла, а не половину. –

+0

Ах, это звучит идеально. Но когда вы говорите переименование, вы хотите сначала удалить оригинал с помощью отдельного оператора, или автоматически переименовать (и атомарно?) Удалить оригинал перед переименованием? – JoeCool

2

Или, как очень простой kludge, читатель создает временный файл (говорит, .lock) перед началом чтения и удаляет его впоследствии. Запись не управляет файлом, пока существует .lock.

Так работает Open Office (и другие), и это, вероятно, самый простой в реализации, независимо от того, какая платформа.

+1

Но также приводит к ужасным ужасным условиям гонки. –

+0

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

+2

Билли и Джо, вы ошибаетесь. Откройте файл '.lock' с' O_CREAT | O_EXCL', и вы по существу получили себе атомный (** не ** первый тест на существование, а затем создать, пусть 'open' сделает это для вас атомарно.) Что * будет * становятся сложными для обработки - это случаи, когда процесс, удерживающий блокировку, умирает без удаления файла '.lock'. – vladr

3

Если вы хотите пойти с Windows API, открыв файл с помощью CreateFile и пройдя в 0 для dwShareMode, это не позволит открывать файл другому приложению.

Из документации:

Предотвращает другие процессы от открытия файла или устройства, если они запрос удаления, чтения или записи.

Тогда вам придется использовать ReadFile, WriteFile, CloseFile и т. Д., А не стандартные функции библиотеки C.

0

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

0

Вам не удалось сохранить несколько изображений? ('n' звучит как хорошее число :-)

Не слишком много, чтобы заполнить ваш диск, но наверняка 3 будет достаточно? если нет, вы пишете быстрее, чем можете обрабатывать, и у вас есть фундаментальная проблема anyhoo (настройте на обнаружение «n»).

Циклически переписывать.

1

Joe, предложено множество решений; Я прокомментировал некоторые из них, но я хотел бы звонить в с общей точки зрения и некоторые особенности и рекомендации:

У вас есть следующие варианты:

  1. использование файловая система блокировки: под Windows, оба читатель и писатель открываются (и создают с помощью CREATE_ALWAYS disposition, соответственно) общий файл в OF_SHARE_EXCLUSIVE mode; имеют как читатель и писатель готов обрабатывать ERROR_SHARING_VIOLATION и повторить попытку через некоторое заранее определенного периода времени (например, 250ms)
  2. использование переименования файлов по существу передать файл собственности: есть писатель создать писатель-частный файл (например shared_file.tmpwrite), напишите ему, закройте его, затем сделайте его общедоступным для читателя, переименовав его в согласованное «общедоступное» имя (например, просто shared-file); периодически читайте читателю тест на наличие файла с согласованным «общедоступным» именем (например, shared-file) и, когда он найден, попытайтесь сначала переименовать его в имя-читатель-личный адрес (например, shared_file.tmpread) прежде чем открыть его читателю (под именем читателя); под Windows use MOVEFILE_REPLACE_EXISTING; операция переименования не должна быть атомарным для этой работы
  3. использование других форм interprocess communication (IPC): под Windows, вы можете create a named mutex и иметь как читатель и писатель попытку создать (существующий мьютекс будет возвращен, если он уже существует), то приобрести названный семафор перед открытием общего файла для чтения или записи
  4. реализовать свои собственные файловой системы спинками блокировки: воспользоваться open(O_CREAT|O_EXCL) или под Windows, из CREATE_NEW disposition в атомарно создать приложение lock file; в отличие от OF_SHARE_EXCLUSIVE подхода выше, было бы до вас, чтобы иметь дело с устаревшими файлами блокировки (т.е. файлы блокировки, оставленные в процессе, который не закрыли изящно например, после аварии.)

Я бы реализовать метод 1.

Способ 2 также будет работать, но это в некотором смысле переосмысливает колесо.

Способ 3, возможно, имеет преимущество, позволяющее вашему процессу считывания ждать процесса записи и наоборот, устраняя необходимость произвольных задержек сна между повторами методов 1 и 2 (опрос); однако, если вы в порядке с опросом, то вы все равно должны использовать метод 1

Метод 4 приведен только для полноты, поскольку он является сложным для реализации (когда файл блокировки обнаружен устаревшим, например, проверяя, является ли PID содержащиеся в нем, все еще существуют, несколько процессов могут потенциально конкурировать за его удаление, что вводит условие гонки, требующее второй блокировки, который, в свою очередь, может стать устаревшим и т. д., например,:

  • процесс А создает файл блокировки, но умирает без удаления файла блокировки
  • процесс перезапускает и пытается получить файл блокировки, но понимает, что несвежий
  • процесс B выходит из задержки сна и также пытается получить файл блокировки, но понимает, что он устарел
  • процесс A удаляет файл блокировки, который, как он знал, был устаревшим, и воссоздает его, по существу, восстанавливает блокировку
  • процесс B удаляет файл блокировки, который он) думает, что это устаревшее (хотя на данный момент оно уже не устарело и принадлежит процессу A) - нарушение
Смежные вопросы