Проблема Читателя Писателя - PullRequest
0 голосов
/ 25 марта 2009

Извините, если я снова задаю тот же вопрос, но хочу подтвердить!

У меня есть два процесса P1 и P2.

P1 - писатель (продюсер).
P2 - ридер (потребитель).

Существует некоторая общая память или файл, в который записывает P1, и как только P1 записывает, P2 должен быть уведомлен о чтении.

Теперь, согласно моему пониманию, псевдокод для P1 должен быть

.
Open shared file
Create a named event("Writedone") to signal write for P2 process
Do some processing on file
Mutex.Lock()
Write to File
Mutex.Unlock()
Signal named Event.
CloseHandle on file

Сейчас в P2

Open handle to Shared file
Open handle to named event
WaitForSingleEvent on named event("Writedone")
Read from file
CloseHandle on file

Вопросы:

  1. Требуется ли иметь блокировку в считывателе? Читатель просто прочитает файл и не изменит его. Так что я думаю, что в ридере не требуются блокировки. Мысли? Может ли что-то пойти не так без замков?
  2. Я открываю и закрываю дескрипторы файла каждый раз во время чтения и записи. Я думаю, что это не обязательно. Я могу открыть дескриптор файла в конструкторе и закрыть его в деструкторе читателя и писателя. Но могу ли я прочитать из файла, когда он используется в письменной форме?

РЕДАКТИРОВАТЬ: Каждый раз, когда писатель пишет 10 байтов в конце файла и читатель должен прочитать последние 10 байтов, написанных писателем.

Ответы [ 5 ]

1 голос
/ 25 марта 2009

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

  1. Блокировка только во время записи не имеет смысла. Это только добавляет некоторые накладные расходы, но не предотвращает одновременный доступ, пока читатель также не будет правильно заблокирован.
  2. Блокировка необходима, если файловые операции, которые изменяют структуры, связанные с дескрипторами файла, не синхронизируются каким-либо образом. Может случиться, что P1 может начать запись в файл, когда P2 все еще читает. Если операции чтения и записи изменяют одни и те же системные структуры без какой-либо синхронизации, вы получите поврежденные данные. Трудно сказать, так ли это, потому что вы не упомянули, какую конкретную функцию (библиотеки) вы использовали. Файловые операции синхронизируются в большинстве систем, поэтому это не должно быть проблемой.
  3. Из того, что вы написали о "10-байтовых порциях информации", явная блокировка кажется ненужной (если только # 2 не навязывает ее). P1 производит квант данных. Когда данные готовы для чтения, P1 уведомляет об этом P2 (по событию; во всяком случае, передача события должна быть внутренне синхронизирована). P2 знает, что он может прочитать квант данных и затем должен ждать последующего уведомления. Может случиться, что последующее уведомление будет отправлено до обработки предыдущего. Итак, события нужно как-то ставить в очередь. Вы также можете использовать семафор вместо уведомления о событиях.
0 голосов
/ 26 марта 2009

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

0 голосов
/ 25 марта 2009

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

Producer writes and signals
Consumer receives signal
Consumer opens the file
Producer fires again and writes another 10 bytes
Producer signals
Consumer reads the last 10 bytes
Consumer closes the file

Что произойдет дальше, зависит от того, является ли указанное событие событием ручного сброса или автоматического сброса. Если это автоматический сброс, то Потребитель увидит второй сигнал и вернется и снова прочитает то же самое. Если это ручной сброс, то Потребитель собирается сбросить событие и пропустить последнее, что написал Производитель.

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

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

0 голосов
/ 25 марта 2009
  1. Вам необходимо заблокировать мьютекс в считывателе, если писатель может начать запись в любое время. Убедитесь, что мьютекс является именованным, чтобы P2 мог его открыть.

  2. Если вы откроете файл с помощью FileShare.ReadWrite в обоих процессах, вы можете оставить его открытым.

В читателе вам, возможно, придется искать место, куда вы нажали EOF, прежде чем сможете читать снова.

Если вы уверены, что писатель всегда добавляет данные и можете сказать, где заканчивается запись (например, они всегда составляют 10 байт), и вы можете принять небольшую задержку, а писатель всегда пишет полные записи, вы можете это без мьютексов и событий вообще. Откройте файл с помощью FileShare.ReadWrite и в считывателе продолжайте искать в том же месте и пытаться прочитать вашу запись, и поспите секунду, если не можете. Если вам удастся прочитать целую запись, у вас есть одна. Определите свою позицию и вернитесь назад, чтобы найти это место и попробуйте снова прочитать. Это похоже на то, как tail -f работает в Unix.

0 голосов
/ 25 марта 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...