スレッドの同期

CLRのスレッド同期メカニズムは、Win32のスレッド同期メカニズムのオブジェクトラッパーにすぎない。

volatile read

  • メインメモリから読み取りをおこなうことを強制(CPUキャッシュ無効化)
  • CPUキャッシュ対策
    • マルチコアCPU下でCPUキャッシュを使用すると、複数スレッドが同じフィールドに同時アクセスしても異なる値を取得してしまう場合がある
  • C#ではvolatileキーワードを指定

相互ロック

        static int counter = 0;
        static void Main(string[] args)
        {
            Thread a = new Thread(new ThreadStart(increment_action));
            Thread b = new Thread(new ThreadStart(increment_action));
            Thread c = new Thread(new ThreadStart(increment_action));
            a.Start();
            b.Start();
            c.Start();


            a.Join();
            b.Join();
            c.Join();
            Console.WriteLine(counter);
            Console.ReadLine();
        }
        static void increment_action()
        {
            for (int i = 0; i < 100; i++)
            {
                Interlocked.Increment(ref counter);
            }
        }

こんな感じだろうか?

Monitorと同期ブロック

  • C#ではlockステートメントで記述できる。
  • CLRは初期化の際に同期ブロックの配列を確保する。
  • オブジェクトは初期化の際、同期ブロックインデックスを負の値とする。
  • オブジェクトが同期ブロックに入ったとき、CLRが使用していない同期ブロックを配列から探し、同期ブロックインデックスが見つかった要素のインデックスを指すように設定する。
lock(this)は危険
  • 誰からでもロックができてしまう
  • 内部にprivateなObject型のオブジェクトを作成し、それをロック用に利用すべき。

カーネルオブジェクト

  • セマフォミューテックス、イベント
    • ラッパクラスは全てWaitHandleを継承している。
  • WaitHandleは、カーネルオブジェクトハンドルを内部フィールドに持つ。
  • いずれの操作もCLR上の同期に比べたら遅い。

ReaderWriterLock

いくつかの問題があると指摘されている。

  • 遅い
  • 読み取りスレッドが優先されるため、書き込みが遅い。
  • 再帰をサポートしている(これは危険とのこと)