CSharp0005 のバックアップ(No.1) - PukiWiki

CSharp?

なぜLockするか?何をLockする?
[edit]

スレッドの最も効率的な方法は非同期ですね、つまり、各スレッドは、実行されて使用する時には相互依存、待つがないです。しかし、複数のスレッドがあるリソースをアクセスする時、同期メカニズムが必要、このリソースの扱いは、同じ時間で一つのスレッドしか操作できないように制御する必要があります。すなわち、その操作の原子性を保証するようにします。Lockは、最もよく使用される同期方法、 フォーマット:

Lock(objectA)
{
  //処理A
}

意味は:

このページのトップへ

lock(this)がいいか?
[edit]

ソースコードの例を見ましょう

using System;
using System.Threading;
namespace Namespace1
{
   class C1
   {
       private bool deadlocked = true;

       //このメソッドはLockを利用している、Lockされている処理は同時にひとうのスレッドのみアクセスできるようにしたいです。
       public void LockMe(object o)
       {
           lock (this)
           {
               while(deadlocked)
               {
                   deadlocked = (bool)o;
                   Console.WriteLine("Foo: I am locked :(");
                   Thread.Sleep(500);
               }
           }
       }

       //すべてのスレッドで同時にアクセスできるメソッド
       public void DoNotLockMe()
       {
           Console.WriteLine("I am not locked :)");
       }
   }

   class Program
   {
       static void Main(string[] args)
       {
           C1 c1 = new C1();

           //t1スレッド内にLockMeを呼び出して、deadlockをtrueにすると、デッドロックが発生します。
           Thread t1 = new Thread(c1.LockMe);
           t1.Start(true);
           Thread.Sleep(100);

           //メインスレッドlock c1
           lock (c1)
           {
               //Lockしないメソッドを呼び出す
               c1.DoNotLockMe();
               //Lockするメソッドを呼び出す、デッドロックを解除してみる
               c1.LockMe(false);
           }
       }
   }
t1スレッド内に、LockeMeがLock(this)、つまりはMainメソッド中のC1、この場合t1スレッド中のLock処理が実行完了まで、メインスレッド中にLock(C1)を呼び出しても、C1をアクセスできません、つまりすべてC1関連の処理が完成できません。だからC1.DoNotLockMe()は実行されていません。~

C1のコードを修正します。

   class C1
   {
       private bool deadlocked = true;
       private object locker = new object();

       //このメソッドはLockを利用している、Lockされている処理は同時にひとうのスレッドのみアクセスできるようにしたいです。
       public void LockMe(object o)
       {
           lock (locker)
           {
               while(deadlocked)
               {
                   deadlocked = (bool)o;
                   Console.WriteLine("Foo: I am locked :(");
                   Thread.Sleep(500);
               }
           }
       }

       //すべてのスレッドで同時にアクセスできるメソッド
       public void DoNotLockMe()
       {
           Console.WriteLine("I am not locked :)");
       }
   }

 今回はあるオブジェクト(locker)をロック対象にする、LockMe中にすべての対象をロックするではなく、Lockerオブジェクトだけをロックしています。 実行してみたら、t1がデッドロック現象がまた出ましたが、DoNotLockMe()はメインスレッドからアクセスできます、LockMe()はアクセスできません。(理由はロックされているlockerオブジェクトはリリースされていませんので)

ポイント:

  1. Lock(this)の欠点は一つのスレッド(本例のt1)、あるメソッド中にlock(this)を実行すると、this(クラス)をロックされ、ほかのすべてのスレッドがクラスのインスタンスをアクセスできなくなります。ほかのスレッド(例のメインスレッド)中に、クラスを利用時、もlock(c1)を使用していますから。
  2. ロックするのはロック内の処理だけではなく、ロック自身もスレッドセーフ
  3. ほかの操作への影響がないprivateなオブジェクトをロックする対象にする。



トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

PCpዾyǗlgĂ܂}WŔ܂z 萔O~ył񂫁z Yahoo yV NTT-X Store

z[y[W ̃NWbgJ[h COiq ӂ邳Ɣ[ COsیI COze