ここでひどく質問しました 複数のスレッドで変数をロックします わかりやすくするために、ここで質問します。正しく質問できることを願っています。
classA
creates instance of classB
has methodA that can update & uses classB's myVar
has methodB that can update & uses classB's myVar
classB
has a variable myVar
methodAとmethodBは両方とも別々のスレッドで実行できます(mainからの新しいスレッドで呼び出されます)。これがスレッドセーフであることを確認するにはどうすればよいですか?
lock
キーワードを使用して、複数のスレッドで同時に実行できるコードを保護します。
public class ClassA
{
private ClassB b = new ClassB();
public void MethodA()
{
lock (b)
{
// Do anything you want with b here.
}
}
public void MethodB()
{
lock (b)
{
// Do anything you want with b here.
}
}
}
lock
は、ステートメントで使用されるオブジェクトインスタンスを保護またはロックしないことに注意することが重要です。代わりに、オブジェクトは、同じオブジェクトインスタンスを使用する別のセクションがすでに実行されている場合に実行を防止する必要があるコードのセクションを識別する方法として使用されます。つまり、lock
ステートメントで任意のオブジェクトインスタンスを使用でき、それでもClassB
のメンバーにアクセスしても安全です。
最も簡単な解決策:ClassBのインスタンスをスレッド間で共有しないでください。
つまり、スレッド宣言を使用して新しいClassBをインスタンス化し、パラメーターとして送信します。
残念ながら、スレッドセーフの観点から何が成功と見なされるかについての質問はややあいまいです。スレッドセーフとは、複数のスレッドが実行されている場合に操作が正しく機能することを意味します。
欠落しているように見えるのは、classA.methodA(...)またはclassA.methodB(...)を呼び出す別のスレッドの前に、classA.methodAまたはclassA.methodBがclassB.myVarで操作を終了する必要があるかどうかです。それはあなたが必要とするであろうロックパターンのタイプを決定するでしょう。
たとえば、値の読み取りを保証する必要がある場合は、次のようになります。
public class classA
{
private classB b = new classB();
public void methodA()
{
lock (b)
{
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar
}
}
public void methodB()
{
lock (b)
{
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar
}
}
}
別の例では、b.myVarがキャッシュのように同期する必要があるコレクションのタイプである場合、次のようになります。
public class classA
{
private classB b = new classB();
public void methodA()
{
// Read b.myVar for missing collection item
lock (b)
{
// Check for missing collection item again. If not missing, leave lock
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar with new array item
}
}
public void methodB()
{
// Read b.myVar for missing collection item
lock (b)
{
// Check for missing collection item again. If not missing, leave lock
// Operation without calling methodA() or methodB()
// Read b.myVar
// Update b.myVar with new array item
}
}
}
lock ステートメントのドキュメントを確認してください。
ClassB
は変数を公開するべきではありません(おそらくデータメンバーを意味します)。代わりに、プロパティまたはメソッドのセットを公開し、 ReaderWriterLockSlim を使用して複数のスレッドを処理します。