8

階層化された通信インターフェイスを備えたアプリケーションを作成しています。
これは、アプリケーションのユーザー インターフェイス部分から通信を抽象化し、さらにスケーラビリティと保守性を高めるために行われました。
例えば:

代替テキスト

上の図の各ボックスを個別のクラスと考えてください。
Generic Comms Interface は、トランザクション データと通信の「正常性」を表す文字列変数を設定します。これらは、一連のパブリック関数呼び出しを通じてアプリケーションにコピーされます。たとえば、アプリケーションは App-Sub-System を呼び出します。

class Application
{
   private void SomeUpdateFunction()
   {
      this.textBox1.AppendText(this.AppSubSystem.GetText());
   }
}

class AppSubSystem
{
   public string GetText()
   {
      return this.GenericCommsInterface.GetText();
   }
}

class GenericCommsInterface
{
   public string GetText()
   {
      string sRetVal = this.sText; // sText is populated by other functions in the class.
      this.sText = null; // Suspected race condition is here.
      return sRetVal;
   }
}

sTextクラス内の他の関数によって非同期に設定されます。と次の行の
間で競合状態が発生していると思います。 誰かがこの競合状態を回避または防止する方法を提案できますか? ヘルプを使用しますか、それともこれを行うべき別の方法はありますか?string sRetVal = this.sText;this.sText = null;
StringBuilder

4

3 に答える 3

4

タッチしたいときはいつでもロックを取得する必要がありますthis.sText-それを更新する関数とGetText関数で。これにより、(スレッドにロックがあると仮定して) 他のスレッドが座って現在のスレッドが完了するまで待機するため、一度に 1 つのスレッドだけがそれをいじることが保証されます。

たまたまインターンされた文字列、またはロックされた操作の途中で切り替えられた文字列をロックすると(部外者の観点からはロックが解除された)、本当に悪いモジョが発生する可能性があるため、部分的にロックを簡素化するために、StringBuilderを使用することをお勧めします。 . このようなものが役立ちます:

lock (this.sbText)
{
    sRetVal = this.sbText.ToString();
    this.sbText.Length = 0;
}

別の方法として、 をロックすることもできますがthis、これは見苦しいものです。奇妙な副作用 (他のオブジェクトがこのオブジェクトのロックを取得しようとした場合など) を回避するために、ロックは可能な限り非公開にする必要があります。変更中にそうしないでくださいsbText)。

于 2010-07-21T21:33:47.213 に答える
1
public string GetText()
{
   lock( someObject )
   {
      string sRetVal = this.sText; // sText is populated by other functions in the class.
      this.sText = null; // Suspected race condition is here.
      return sRetVal;
   }
}    

あなたのセットで

lock( someObject )
{
    //...
    this.sText = value;
}
于 2010-07-21T21:33:00.583 に答える
1

このコードは、sText を保護していないため、スレッド環境では確実に機能しません。アクセスするすべての人をロックする必要があります。

于 2010-07-21T21:33:14.593 に答える