2009-03-05 5 views
6

私は質問を投稿するつもりでしたが、それを事前に把握して、質問と回答、または少なくとも私の所見を投稿することに決めました。.NETでの匿名の代理人の使用ThreadPool.QueueUserWorkItem

ForeachループでThreadPool.QueueUserWorkItemが呼び出されるWaitCallbackとして匿名の代理人を使用すると、同じ1つのforeach-valueが各スレッドに渡されるように見えます。私はWorkWithOneThingに渡された各「シングは」「もの」リスト内の最後の項目に対応することが観察物事で16個のシングインスタンスのコレクションのために

List<Thing> things = MyDb.GetTheThings(); 
foreach(Thing t in Things) 
{ 
    localLogger.DebugFormat("About to queue thing [{0}].", t.Id); 
    ThreadPool.QueueUserWorkItem(
     delegate() 
     { 
      try 
      { 
       WorkWithOneThing(t); 
      } 
      finally 
      { 
       Cleanup(); 
       localLogger.DebugFormat("Thing [{0}] has been queued and run by the delegate.", t.Id); 
      } 
     } 
} 

これは、代理人が 't'外部変数にアクセスしているためです。私は、Thingをパラメータとして匿名デリゲートに渡すことも実験しましたが、その動作は正しくありませんでした。

名前付きWaitCallbackメソッドを使用するコードを再作成し、メソッド 'Th'をメソッドに渡すと、ビオラ... Thingsのiインスタンスが正しくWorkWithOneThingに渡されました。

レッスンは並行していると思います。私はParallel.Forファミリがこれに対処しているとも思っていますが、その時点でライブラリはオプションではありませんでした。

希望すると、他の誰かに時間を節約できます。

ハワード・ホフマン

+0

あなたはこのコードをコンパイルしようとすると、エラーを取得することはありません「System.Threading.WaitCallback 0 『引数」を取らない』」あなたは何のparam – ram

+0

ラムを指定しないと - を変更してみてください上記の宣言から: デリゲート(){ ...} デリゲートに{... } Iはである持っていたものである 私の変更をする前に。これがあなたを助けることを願っています –

答えて

7

これが正しいこと、およびC#は閉鎖内外の変数をキャプチャする方法を説明します。これは並列性に関する問題ではなく、むしろ匿名のメソッドとラムダ式についての問題です。

This questionでは、この言語機能とその意味について詳しく説明しています。

+0

この記事はまた役に立ちました:http://www.managed-world.com/archive/2008/06/13/lambdas---know-your-closures.aspx –

1

これはクロージャを使用するときによく起こる現象で、LINQクエリを作成するときに特に顕著です。クロージャーはその内容を参照するのではなく、変数を参照していますので、ループの中でtの値をとり、クロージャー内の変数を参照する変数を指定することができます。これにより、匿名デリゲートの各バージョンが異なる変数を参照するようになります。

関連する問題