2011-02-19 10 views
1
List<int> data=new List<int>(); 
foreach(int id in ids){ 
    var myThread=new Thread(new ThreadStart(Work)); 
    myThread.Start(id); 
} 


Work(){ 
} 

メソッド受信したIDに対して処理を行い、その結果をデータリストに追加しますか?各スレッドからコレクションにデータを追加するにはどうすればよいですか?私のコードはどのように見えますか?ありがとうスレッドを使用する - コレクションに追加

+1

コレクションを手動でロックするか、.NETの並行コレクションのいずれかを使用する必要があります。しかし、このような単純なもののためにTasksを使用することをお勧めします。スレッドが引き起こす複雑さの多くをきちんと管理しています。 – Crisfole

+0

いつものようにジョンは私が忘れるものを考えます。間違いなく彼の方法にこだわるべきです。 – Crisfole

答えて

7

.NET 4を使用している場合は、代わりにParallel Extensionsを使用することを強くお勧めします。例えば:

Workである
var list = ids.AsParallel() 
       .Select(Work) 
       .ToList(); 

public int Work(int id) 
{ 
    ... 
} 

それが適切idを受信できるようにします。

var list = ids.AsParallel() 
       .Select(id => Work(id)) 
       .ToList(); 

いずれかの方法、これはあなたが本当に必要以上のスレッドを作成しないように、そしてあなたなしで物事のスレッドの安全性の側面に対処します:あなたはメソッド変換に熱心でないなら、あなたはラムダ式を追加することができます自分でロックを管理する必要があります。

+0

AsParallel()を使うとうまくいきますが、2つ以上のスレッドを並行して動作させることはできますか? – Ryan

+0

@Ryan:もちろんです。並列化を制御するにはさまざまな方法があります。通常、使用可能なコアの数に応じて自動的にスケールされますが、WithDegreeOfParallelismのような方法では、状況を調整することができます。 –

0

スレッドからデータを(コールバックを使用して)渡したり取得したりすることができます。 MSDN articleを参照してください。

例:すべての

public class SomeClass 
    { 
     public static List<int> data = new List<int>(); 
     public static readonly object obj = new object(); 

     public void SomeMethod(int[] ids) 
     { 
      foreach (int id in ids) 
      { 
       Work w = new Work(); 
       w.Data = id; 
       w.callback = ResultCallback; 
       var myThread = new Thread(new ThreadStart(w.DoWork)); 
       myThread.Start(); 
      } 
     } 

     public static void ResultCallback(int d) 
     {   
      lock (obj) 
      {   
       data.Add(d); 
      } 
     } 

    } 

    public delegate void ExampleCallback(int data); 
    class Work 
    { 
     public int Data { get; set; } 
     public ExampleCallback callback; 

     public void DoWork() 
     {     
      Console.WriteLine("Instance thread procedure. Data={0}", Data); 
      if (callback != null) 
       callback(Data); 
     } 

    } 
+0

ロックを避けるためにデータを共有しないことをお勧めします。しかし、あなたは結果を逃している! 'data'リストに何かを追加する部分です! –

+1

スレッドが結果をリストにプッシュしている場合、ロック/同期を回避する手段はありません(暗黙的かもしれません)。メインスレッドがワーカースレッドからデータを取得する場合は、ワーカーが作業を終了するタイミングを知る必要があります。 – Vlad

+0

@Martinho Fernandes @Vladありがとう、私はそれを更新しました。 – Adeel

1

まず、あなたはロックを使用してマルチスレッドアクセスを保護する必要があります。次に、パラメータをスレッドに渡す必要があります(または、ローカル変数を取得できるlambdaを使用します。ループ変数を取得すると、ループ中に値が変更されるため、ローカルコピーが必要です)。

object collectionLock = new object(); 
List<int> data = new List<int>(); 

foreach (int id in ids) 
{ 
    Thread t = new Thread(Worker); 
    t.Start(id); 
} 

void Worker(object o) 
{ 
    int id = (int)o; 
    lock(collectionLock) 
    { 
     data.Add(id); 
    } 
} 
+2

WRT: "ループ変数をキャプチャすることはできません"(実際にキャプチャすることができます - それは常に同じ変数です;-)これを回避するには...詳細...私は 'foreach(var _x in ... ){var x = _x; ...} '、それは重要です。 –

+0

@pst:はい、私はこれを正確に意味しました。キャプチャされた変数はループ内で再利用されるので、それをキャプチャし、単純な方法で使用すると予期しない動作が発生します。 – Vlad

+0

@pst:答えを編集してより明確にしました。提案していただきありがとうございます! – Vlad

関連する問題