7

GetBuffer()を呼び出すことにより、MemoryStreamオブジェクトのデータバッファーに直接データを書き込むコードが少しあります。また、PositionプロパティとSetLength()プロパティを適切に使用および更新します。

このコードは99.9999%の確率で正しく機能します。文字通り。非常に多くの100,000回の反復ごとにのみ、それは吠えます。特定の問題は、MemoryStreamのPositionプロパティが適切な値ではなく突然ゼロを返すことです。

ただし、0をチェックし、PositionやLengthなどのMemoryStreamプロパティのログを別のメソッドに含む例外をスローするコードが追加されました。それらは正しい値を返します。同じメソッド内にロギングをさらに追加すると、このまれな状態が発生した場合、この特定のメソッド内では位置がゼロになるだけであることがわかります。

わかった。明らかに、これはスレッドの問題である必要があります。そして、おそらくコンパイラの最適化の問題です。

ただし、このソフトウェアの性質は、スケジューラーを使用した「タスク」によって編成されるため、いくつかの実際のO / Sスレッドのいずれかがいつでもこのコードを実行できますが、一度に複数のコードを実行することはできません。

したがって、通常、同じスレッドがこのメソッドに使用され続け、まれに別のスレッドが使用されることがあると思います。(スレッドIDをキャプチャして比較することにより、この理論をテストするためのアイデアをコーディングするだけです。)

次に、コンパイラの最適化により、別のスレッドが正しい値を取得することはありません。「古い」値を取得します。

通常、このような状況では、問題の変数に「volatile」キーワードを適用して、それが修正されるかどうかを確認します。ただし、この場合、変数はMemoryStreamオブジェクト内にあります。

他に何かアイデアはありますか?それとも、これは独自のMemoryStreamオブジェクトを実装する必要があることを意味しますか?

よろしくお願いいたします。ウェイン

編集:このメソッドへの呼び出しの総数をカウントし、ManagedThreadIdが最後の呼び出しと異なる回数をカウントするテストを実行しただけです。スレッドを切り替えるのはほぼ正確に50%の時間で、スレッドを交互に切り替えます。したがって、上記の私の理論はほぼ間違いなく間違っているか、エラーがはるかに頻繁に発生します。

編集:このバグはめったに発生しないため、バグが実際になくなったと感じる前に、バグなしで実行するのに1週間近くかかります。代わりに、問題の性質を正確に確認するために実験を実行することをお勧めします。

編集:現在、ロックは、MemoryStreamを使用する5つのメソッドのそれぞれでlock()ステートメントを介して処理されます。

4

1 に答える 1

6

(これを確認するには、実際に模範的なコードが必要です。)

MemoryStreamメンバーはスレッドセーフ(たとえば)として文書化されていないため、一度に1つのスレッドからPositionこのインスタンス(または論理的には一部のオブジェクトへの参照)にのみアクセスできるようにする必要があります。MemoryStream

ただし、スレッドアフィニティMemoryStreamがあるとは文書化されていないため、そのようなアクセスが同時でない限り、別のスレッドからインスタンスにアクセスできます。

スレッド化は困難です(このQ&Aでは公理的です)。

2つのスレッドが両方とも同じインスタンスに同時にアクセスする同時アクセスが行われていることをお勧めします。これにより、インスタンスの状態の一部が破損する場合があります。

私は、ロックを可能な限り単純に保ち(非常に巧妙にしようとし、ロックを制限することは、バグを見つけるのが非常に難しい原因になることがよくあります)、物事を機能させるようにします。マルチコアシステムでのテストも役立つ場合があります。プロファイリングで正味(アプリケーション全体)の大幅な増加の可能性があることが示された場合にのみ、ロックを最適化してみてください。

于 2010-05-13T09:26:32.603 に答える