|
ロックキーワードは、与えられたオブジェクトに対してミューテックスを取り、文を実行し、ロックを解放することで、文のブロックをクリティカルゾーンとしてマークします。
lock文は基本的にMonitor.EnterとMonitor.Exitを使用します。つまり、lock(this)が実行されたときにMonitor.Enter(this)が実行され、Monitor.Exit(this)がカール括弧の最後に実行されます。その意味は何ですか?任意のオブジェクトに対して、メモリの最初の部分はすべてのメソッドのアドレスであり、後半はインデックスです。 彼はCLRのSyncBlockキャッシュエリアにあるSyncBlockを指さします。それはどういう意味でしょうか? つまり、Monitor.Enter(Object)を実行する際に、オブジェクトのインデックス値が負の場合は、SyncBlockキャッシュからSyncBlockを選択し、そのアドレスをオブジェクトのインデックスに配置します。 これによりオブジェクトでマークされたロックが完了し、他のスレッドは再びMonitor.Enter(object)操作を実行し、正のオブジェクトのインデックスを取得して待機します。 インデックスが負になるまで、つまりスレッドはMonitor.Exit(object)を使ってインデックスを負に変えます。 ロックを使用する際に注意すべきこと:
1.ロックはnull値をロックできませんオブジェクトはnullを指し示すことができますが、nullを解放する必要はありません。 (関連項目:全零の理解) 2.lockは文字列型をロックできませんが、参照型でもあります。 文字列タイプはCLRによって「ホバー」されているためです つまり、プログラム全体で任意の文字列のインスタンスは1つだけ存在し、その同じオブジェクトがすべての実行中のアプリケーションドメインのスレッドでそのテキストを表します。 したがって、アプリケーションプロセスのどこにいても同じ内容の文字列にロックがかけられている限り、アプリケーション内のその文字列のすべてのインスタンスはロックされます。 したがって、永続化されないプライベートまたは保護されたメンバーはロックするのが最善です。 3.locklock オブジェクトはプログラムブロックのメモリ境界です 4. 値型はロックできません。前のテキストで赤字で「オブジェクトが解放される」と表示されており、値型は参照型ではないからです 5.lockは、プログラムによって制御されていないパブリック型やオブジェクトのロックを回避します。 例えば、インスタンスが公開アクセス可能の場合、ロック(this)は制御されていないコードでもオブジェクトをロックできるため問題になることがあります。 これにより、同じオブジェクトを解放するために2つ以上のスレッドが同時に待つデッドロックが発生することがあります。 公開データ型(オブジェクトではなく)をロックすることも同じ理由で問題を引き起こすことがあります。 lock(this)を使う場合、クラスメンバー変数の値はクリティカルゾーンに属さないメソッドによって変更されることがあります
応用シナリオ:マルチスレッド操作による公開変数の値の不確実な例外を防ぎ、操作のセキュリティを確保するためによく用いられます
- // statements_lock2.cs
- using System;
- using System.Threading;
- class Account
- {
- private Object thisLock = new Object();
- int balance;
- Random r = new Random();
- public Account(int initial)
- {
- balance = initial;
- }
- int Withdraw(int amount)
- {
- // This condition will never be true unless the lock statement
- // is commented out:
- if (balance < 0)
- {
- throw new Exception("Negative Balance");
- }
- // Comment out the next line to see the effect of leaving out
- // the lock keyword:
- lock(thisLock)
- {
- if (balance >= amount)
- {
- Console.WriteLine("Balance before Withdrawal : " + balance);
- Console.WriteLine("Amount to Withdraw : -" + amount);
- balance = balance - amount;
- Console.WriteLine("Balance after Withdrawal : " + balance);
- return amount;
- }
- else
- {
- return 0; // transaction rejected
- }
- }
- }
- public void DoTransactions()
- {
- for (int i = 0; i < 100; i++)
- {
- Withdraw(r.Next(1, 100));
- }
- }
- }
- class Test
- {
- static void Main()
- {
- Thread[] threads = new Thread[10];
- Account acc = new Account(1000);
- for (int i = 0; i < 10; i++)
- {
- Thread t = new Thread(new ThreadStart(acc.DoTransactions));
- threads[i] = t;
- }
- for (int i = 0; i < 10; i++)
- {
- threads[i].Start();
- }
- }
- }
コードをコピーします
|