DSPACK コンポーネント ライブラリを使用して、Delphi 6 で記述された DirectShow プッシュ ソース フィルタがあります。プッシュ ソース フィルターの FillBuffer() 呼び出しのブロック戦略を実装しています。プッシュ ソース フィルターは、バッファーのコレクションに格納されている 1 つ以上のバッファーにオーディオ データを受け取ります。バッファー コレクション内のすべてのメソッドは、クリティカル セクションによって保護されます。
コレクション内の各バッファーには異なるソースからデータが供給されており、各ソースには独自のスレッドがあります。FillBuffer() 呼び出しは、呼び出し元に返されるマージされたバッファーを形成するためにデータが混合されるため、FillBuffer() が提供するように要求されたデータの量を満たすのに十分なデータがコレクション内のすべてのバッファーになるまでブロックされます。
これが、競合状態とデッドロックを回避するために私が考案した戦略です。バッファ ストレージ コレクションには、これを行うisEnoughData()というメソッドがあります。
- コレクション内の他のすべてのメソッドを保護している同じクリティカル セクションを取得します。
- 各バッファーのチェックを繰り返して、各バッファーに現在の要求を満たすのに十分なデータがあるかどうかを確認します。
- 十分なデータがある場合、TRUE を返します
- 十分なデータがない場合、ブロックを容易にするために使用されるMutexを取得し、FALSE を返し、FNumPendingBytesRequested に満たすことができなかった要求されたバイト数を格納します。
- もちろん、戻る前にクリティカルセクションを解放します。
FillBuffer() は次のことを行います。
- isEnoughData() を呼び出します
- TRUE が返された場合は、混合 (マージされたバッファー) データが提供されたサンプルで呼び出し元に返されます。
- FALSE の場合、上記のisEnoughData()呼び出し中にコレクションによって取得されたMutexで WaitForSingleObject() を実行し、十分なデータが表示されるまでブロックします。Mutexを取得すると、コレクションからデータを取得して呼び出し元に返し、Mutexを解放します。
コレクション内の任意のバッファーにデータを追加するストレージ コレクション内のすべてのメソッドは、戻る前に FNumPendingBytesRequested を満たすことができるかどうかを確認します。その場合、Mutexが解放され、それによって FillBuffer() 呼び出しのブロックが解除され、データが取得されて返されます。当然のことながら、コレクションは破棄されるとMutexを解放します。
これは私にはかなり防弾のようです。isEnoughData() への FillBuffer() 呼び出しと、コレクションにデータを追加する他のスレッドとの間の競合状態から適切に保護すると思います。また、競合状態やデッドロックが発生する可能性のある場所もわかりません。私はこれで正しいですか?戦略に関するヒントや注意事項も大歓迎です。
大きな問題: 私が見ることができる唯一の潜在的な問題点は、FillBuffer() がWaitForSingleObject()を呼び出してブロックする前にMutexを解放するのに十分なデータを別のスレッドが追加するかどうかです。しかし、私の理解では、誰も所有していない同期オブジェクトでWaitForSingleObject()を呼び出すと、オブジェクトの所有権がすぐに返されるため、必要なデータが利用可能になったことを意味するため、問題にはなりません。私の理解は正しいですか?