マルチスレッドロックとモニタークラスが機能しない
-
06-07-2019 - |
質問
ファイルの読み取りと書き込みがあります。それが書かれたとき、誰もそれに書こうとしないことを確認する必要があります。
読み取りまたは書き込みのいずれかを許可する関数全体にロックを設定しますが、次のようなエラーが表示されます プロセスは別のプロセスによって使用されているため、ファイル「FILENAME」にアクセスできません。
public static TYPE Property{
get{
data mydata;
Object obj = new object();
Monitor.Enter(obj);
// check if data has not changed
// if it has not, just read
using (Stream stream = File.Open(fileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
//....
}
// else, if data changed, then need to write to file to save the new data
using (Stream stream = File.Open(fileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) {
BinaryFormatter bf = new BinaryFormatter();
try {
bf.Serialize(stream, (data);
}
//DONE processing
Monitor.Pulse(obj);
Monitor.Exit(obj);
return data
}
解決
プロパティが呼び出されるたびにロックする新しいモニターを作成しています。 同じモニターをロックする必要があります。ロックしないと、ロックしてもまったく意味がありません。
「ロック」も使用する必要があります。ステートメント-あなたは待っていることはありませんので、脈打つことは意味がありません。現在、例外がスローされた場合、「漏れ」が発生します。ロック。これは通常非常に悪い問題ですが、とにかくロックを再利用していないので、問題を隠しています。
例:
private static readonly object monitor = new object();
public static TYPE Property
{
get
{
lock(monitor)
{
// check if data has not changed
// if it has not, just read
using (Stream stream = File.Open(fileLocation,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
....
}
// else, if data changed, then need to write to
// file to save the new data
using (Stream stream = File.Open
(fileLocation, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, data);
}
return data;
}
}
}
余談ですが、これはプロパティで実際に期待するよりも多くの作業を行っているように見えます。メソッドがこれ以上意味をなさないと確信していますか?
他のヒント
まあ、Monitor.Enterは、同じオブジェクトをロックしようとするスレッドのアクセスをブロックします。ゲッターを入力するたびに新しいオブジェクトが作成されるため、すべての呼び出し元は、お互いについて何も知らない新しいロックを取得します。
つまり、ロックはありません。
補足として-なぜlockステートメントを使用しないのですか?グローバルロックオブジェクトが必要になります。
グローバル変数とローカル変数の理由は、LOCKが実際に記憶にある参照点をロックダウンしていることです。新しいオブジェクト、つまり" Object obj = new object();"をインスタンス化するたびに、メモリ内に固有のポインターを持つ新しいオブジェクトが作成されます。したがって、LOCKがメモリ内のポイントがロックダウンされているかどうかを確認しようとすると、ロックされません。これは、メモリ内のまったく新しい参照ポイントであり、それを使用するのはプロパティを入力する呼び出し元だけだからです。 Obj変数をグローバルに宣言すると、それは常にメモリ内の同じポイントになり、ロックは実際に検証できます。実際、メモリ内のそのポイントは現在ロックされているか、自己ロックできます。
例:(原油だが、ポイントを得ると思う)
Object obj = new object();
これで、メモリ内に次のようなポイントがあります:
メモリ-
* obj1
プロパティを再度入力し、新しいオブジェクトをもう一度作成します。システムメモリは、次のようになりました...
メモリ-
* obj1
* obj2
最初の旅行で、ロックは「Obj1」をチェックしています。メモリ内。プロパティへの最初の旅行の呼び出し元は、Objのそのインスタンスを使用している唯一の人であるため、ロックするか、ロックするかどうかを確認するのはこれだけです。メモリ内のそのObj参照のコピーを見ているからです。
2回目の旅行で、ロックは「Obj2」にチェックインされます。メモリ内。
グローバル変数を使用すると、メモリ内のそのポイントが保持されるため、ロックは常にメモリ内の同じポイントをチェックします。移動することはなく、常にメモリ内の同じ参照ポイントです。そのため、プロパティのすべての呼び出し元は常にメモリ内の同じ参照ポイントを使用し、ロックは期待どおりに成功します。
特記事項:私は「obj」の寿命を述べていません。私は、これがマルチスレッドプロセスでどのように機能するかを単に述べています。お役に立てば幸いです。