Потоковая безопасность для фильтров DirectShow, которые доставляют выходные данные из рабочего потока - PullRequest
3 голосов
/ 27 марта 2012

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

Наилучшим способом написания этого является написание фильтра с использованием CBaseFilter, CBaseInputPin и CBaseOutputPin, где выборки принимаются на входном выводе и обрабатываются рабочим потоком, который создает и доставляет новые выборки из выходных данных.штырь.Рабочий поток копирует данные входных сэмплов перед началом работы, так что мой фильтр не должен поддерживать ссылку на входные сэмплы вне входного вызова CBaseInputPin :: Receive.

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

Базовые классы DirectShow содержат страшные комментарии для CBaseOutputPin :: Deliver и CBaseOutputPin :: GetDeliveryBuffer, которые я не полностью понимаю (вставлено ниже).

/* Deliver a filled-in sample to the connected input pin. NOTE the object must
   have locked itself before calling us otherwise we may get halfway through
   executing this method only to find the filter graph has got in and
   disconnected us from the input pin. If the filter has no worker threads
   then the lock is best applied on Receive(), otherwise it should be done
   when the worker thread is ready to deliver. There is a wee snag to worker
   threads that this shows up. The worker thread must lock the object when
   it is ready to deliver a sample, but it may have to wait until a state
   change has completed, but that may never complete because the state change
   is waiting for the worker thread to complete. The way to handle this is for
   the state change code to grab the critical section, then set an abort event
   for the worker thread, then release the critical section and wait for the
   worker thread to see the event we set and then signal that it has finished
   (with another event). At which point the state change code can complete */

1 Ответ

2 голосов
/ 27 марта 2012

У вас есть несколько примеров в Windows SDK в \Samples\multimedia\directshow\filters, а в более ранней версии SDK их было еще больше.Это будет, пожалуй, лучший пример кода, который вы можете проверить для практики блокировки.

Фильтр и контакты обычно используют общие критические секции для обеспечения безопасности потока.Например, CTransformFilter :: m_csFilter защищает данные о состоянии фильтра и не только секции, но и выводы также используют секцию.Дополнительный раздел также используется для сериализации потоковых запросов (проталкивание образцов, отправка уведомлений EOS).

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

Применяются регулярные предложения: во избежание взаимных блокировок вы должны убедиться, что ваш порядок блокировки разработан таким образом, что если раздел A может быть заблокирован в потоке, в котором уже заблокирован раздел B, вы должны блокировать только B [на другомthreads], когда без существующей блокировки на A, так что тупик невозможен.

Таким образом, как правило, у вас есть два сценария, в которые попадает большинство сценариев использования:

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