Является ли эта стратегия синхронизации потоков Windows для моего push-фильтра DirectShow (достаточно) пуленепробиваемой?

У меня есть push-фильтр DirectShow, написанный на Delphi 6 с использованием библиотеки компонентов DSPACK. Я реализую стратегию блокировки для вызова FillBuffer() фильтра принудительного исходного кода. Фильтр push-источника принимает аудиоданные в один или несколько буферов, хранящихся в наборе буферов. Каждый метод в коллекции буферов защищен критическим разделом.

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

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

  1. Получает тот же критический раздел, который защищает все другие методы в коллекции.
  2. Выполняет итерацию каждой проверки буфера, чтобы увидеть, достаточно ли в каждом буфере данных для удовлетворения текущего запроса.
  3. Если данных достаточно, возвращается TRUE
  4. Если данных недостаточно, он получает Mutex, используемый для облегчения блокировки, возвращает FALSE и сохраняет запрошенное количество байтов, которое не может быть заполнено в FNumPendingBytesRequested.
  5. Прежде чем вернуться, он освобождает критическую секцию.

FillBuffer() выполняет следующие действия:

  1. Вызовы isEnoughData()
  2. Если TRUE было возвращено, он возвращает смешанные данные (объединенный буфер) вызывающей стороне в предоставленном образце.
  3. Если FALSE, он выполняет WaitForSingleObject() для Mutex, который был получен коллекцией во время вызова isEnoughData(), как описано выше, таким образом блокируя, пока не появится достаточно данных. Когда он получает Mutex, он берет данные из коллекции и возвращает их вызывающей стороне, а затем выпускает Mutex.

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

Это кажется довольно пуленепробиваемым для меня. Я считаю, что он адекватно защищает от состояния гонки между вызовом FillBuffer() для isEnoughData() и другими потоками, добавляющими данные в коллекцию. Я также не вижу мест, где может возникнуть состояние гонки или тупик. Я прав в этом? Любые советы или предостережения по стратегии тоже приветствуются.

Большой вопрос: единственная потенциальная проблема, которую я вижу, - это если другой поток добавляет достаточно данных для освобождения Mutex до того, как FillBuffer() сможет вызвать WaitForSingleObject() и block. Но я понимаю, что вызов WaitForSingleObject() для объекта синхронизации, который никому не принадлежит, сразу же возвращается с владением объектом, поэтому это не должно быть проблемой, поскольку это означает, что необходимые данные теперь доступны. Правильно ли мое понимание?

0 ответов

Другие вопросы по тегам