2009-08-25 12 views
6

は、その後のしばらくスレッド1がMyMethodはを実行しようとするスレッド2ロックを持っているとしましょうのは、私は次のコードスレッドはロックFIFOで待機していますか?

static class ... 
{ 
    static object myobj = new object(); 

    static void mymethod() 
    { 
     lock(myobj) 
     { 
      // my code.... 
     } 
    } 
} 

があるとしましょう。 ロックが解放されるのを待つか、例外をスローしますか?

待機している場合、追加のスレッドが入ってくるとFIFOになるように順序が保証されていますか?

答えて

8

私の回答が更新されました: それらはキューに入れられますが、注文はFIFOであるとは限りません。

は、このリンクをチェックアウト:http://www.albahari.com/threading/part2.aspx

+4

必ずしもそうではありません:http://stackoverflow.com/questions/961869/is-there-a-synchronization-class-that-guarantee-fifo-order-in-c/961904 –

-1

それが待機する、と彼らは同じ順序でされることはありません。あなたはmyobjmymethodの内側に表示されるように取得んどのようにあなたのコードからは明らかではないReaderWriterLockまたはちょうどlock

+1

これらは同じではありません注文。 –

3

以外の何かのようなものを見れば

あなたのニーズに応じて、より高いパフォーマンスを持っているかもしれません。 var myobjは、宣言スコープのローカルスタック変数です(var以降)。その場合、各スレッドはそれの別個のインスタンスを持ち、mymethodはブロックしないことがあります。

更新

全体FIFO引数について、いくつかの背景情報が必要です:CLRはのsyncronizationを提供していません。これをCLRランタイムにサービスとして提供するのがCLR ホストです。ホストはIHostSyncManagerと他のインタフェースを実装し、さまざまな同期化プリミティブを提供します。これは、最も一般的なホストが典型的なアプリケーションホスト(つまり、コンパイルしてexe)であり、これがOS(Win32 APIの古いPetzoldブックプリミティブ)との同期をすべて非表示にしているように思われるかもしれません。しかし、少なくとも2つの主要なホスティング環境があります:ASP.Net(これが何であるか分かりません)とSQL Serverです。 SQL Serverは基本的にOSのプリミティブに触れることなく、SOSのトープにすべてのプリミティブを提供し、SOSプリミティブはロックconvoysを回避するために設計上不公平です(つまり、 FIFOなし)。もう1つの応答のリンクが既に指摘されているように、OSプリミティブは、ロック・コンボーバを避けるのと同じ理由で、不公平な動作を提供し始めています。

あなたが Designing Applications for High PerformanceでリックVicikの記事をお読みくださいロック船団の詳細については

ロックコンボイ

FIFOロックはロック船団を引き起こし を犠牲にして公平性と前方 進歩を保証。 として、彼らは、ランダムコード全体 を分散した場合よりも高い衝突 を生じる基をコードの同じ部分を実行する用語 元々意味いくつかのスレッドが (同じよう 自動車が交通信号によってパケット にグループ化されます)。特定の 現象は私が話していると悪化しています。 暗黙のうちに暗黙のうちに ロック所有権のハンドオフがロックステップの スレッドを保持するためです。

説明すると、スレッドがロックを保持し、ロックを保持している間に が先取りされる例の を考えてみましょう。 その結果、他のすべてのスレッド は、その ロックの待機リストに積み重なります。先取りされたスレッド(この時点でロック の所有者)が再び実行され、ロックが解除されると、 ロックの ロックの所有権が自動的に待機 リストの最初のスレッドに渡されます。そのスレッドは のために実行されないかもしれませんが、 "ホールドタイム"クロック が時間を計っています。以前の所有者 は、通常、待機リストが が護送

+0

あなたは正しいです、それは静的オブジェクト内の静的オブジェクトです、私はあまりにも速く書いています。今修正する – Matt

0

WindowsとCLRが待機の公正(FIFO順)を保証するために最善を試みを永続、一掃され 前に再度ロックを要求します。ただし、ロック待機中のスレッドの順序を変更することが可能で、アラート可能な待機を中心に回転し、すべてのCLRスレッドのロックによりスレッドを警告可能な状態にするシナリオがあります。

すべての実用的な目的のために、注文はFIFOであると仮定できます。ただし、この問題に注意してください。

1

簡単な例では、順序がFIFO

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 

リーチロックのプロセスは、そのロック異なるご覧CAとして実行がこの

Process Lock Reached: 15 
Process Lock Enter: 15 
DoWork Lock Reached: 12 
Process Lock Reached: 17 
DoWork Lock Reached: 11 
DoWork Lock Reached: 10 
DoWork Lock Reached: 13 
DoWork Lock Reached: 9 
Process Lock Reached: 18 
Process Lock Reached: 14 
Process Lock Reached: 16 
Process Lock Exit: 15 
Thread Lock Enter: 9 
Thread Lock Exit: 9 
Process Lock Enter: 14 
Process Lock Exit: 14 
Thread Lock Enter: 10 
Thread Lock Exit: 10 
Thread Lock Enter: 11 
Thread Lock Exit: 11 
Process Lock Enter: 16 
Process Lock Exit: 16 
Thread Lock Enter: 12 
Thread Lock Exit: 12 
Process Lock Enter: 17 
Process Lock Exit: 17 
Thread Lock Enter: 13 
Thread Lock Exit: 13 
Process Lock Enter: 18 
Process Lock Exit: 18 

のようなものをprocedeうことが保証されていないことを教えて入る。

関連する問題