2016-06-25 5 views
1

私はConcurrentBagコレクションを持っています。この中のすべてのアイテムについて、私はいくつかの作業を行うためのタスクを行います。スレッドセーフですconcurrentbagを使ってタスクを作成します

私は、ConcurrentBagを持つParallel.ForEachはスレッドセーフであることを知っていますが、私はこのように並列性を決して行っていません。

私のコードは、このコードは、スレッドセーフであるので、この

public void Work(IList<MyModel> data) 
{ 
    var tasks = new ConcurrentBag<Task>(); 
    var safeData = new ConcurrentBag<MyModel>(data); 
    foreach (var item in safeData) 
    { 
     var task = Task.Factory.StartNew(() => SomeTask(item)); 
     tasks.Add(task); 
    } 
    Task.WaitAll(tasks.ToArray()); 
} 

のように見えますか?

おかげで

EDIT: たぶん、この質問は次のようになります。「アイテム」は、スレッドセーフであるだろうか、反復間の彼の値を変更することができますか?

EDIT 2: このコードがこの範囲に入るかどうかは、problemです。

編集3:彼はループ変数と直接連携する場合、このquestion 、「Wonko SANEは、」問題を抱えています。この問題はConcurrentBagを使って修正できると思っていましたが、いくつかの答えでは、私はConcurrentBagがまったく必要ないと教えてください。したがって:

ループ変数を直接使用するのは良い考えですか?

この値を別の変数にコピーしますか?

ConcurrentBagのループ変数で直接作業するのは安全ですか?

+0

このシングルスレッドコードのどの部分に問題があると思われますか? ( 'SomeTask(item)'を別々のスレッドで実行している部分は無視します。おそらくスレッドセーフです)。 –

+0

あなたは閉鎖について尋ねていますか?あなたは2番目の質問の文言についての説明を提供できますか? – Kote

+1

tasksとsafeDataのコレクションは、* one *スレッドのみが使用します。したがって、常にスレッドセーフであり、ConcurrentBagを使用する点はありません。データ要素上のスレッドは、スニペットからスレッドセーフな方法でそれらのオブジェクトが使用されているかどうかを判断する方法はありません。それぞれのスレッドが別個の要素を扱うためにうまくいく傾向にありますが、要素が同じオブジェクトへのオブジェクト参照を持ち、ワーカースレッドが要素を変更すると問題が発生します。 –

答えて

1

既存の回答に加えて:

問題は、マルチスレッド化または並行性に関するものではありません。約closuresです。

  1. 何が起こっているのかわかっている場合は、直接ループ変数を使用しても構いません。
  2. foreachの場合は、コンパイラのバージョンによって異なります。コードが古いバージョンでコンパイルされると、that very questionで説明されているような問題が発生します。forループを使用する場合は、常にループ変数をコピーする必要があります。詳細はJon's answerのリンクをご覧ください。
  3. すでに言及したように、ConcurrentBagを使用しても結果には影響しません。
    コンパイラのバージョンが4.0.30319.1(MSコンパイラの場合)より古い場合は、ループ変数をクローズするのが安全です。 More info about compiler versions

また、その質問のコメントに記載されているように、このようなケースを強調する静的解析ツールを使用することができます。

3

このコードにはConcurrentBagはまったく必要ありません。ConcurrentBagParallel.ForEachには必要ありません。 Parallel.ForEachの引数はスレッドセーフである必要はありません。

代わりに、あなたは単にあなたがDoSomeTask内部で実行されるコード内でそれを変更している場合にのみConcurrentBagを必要とし、

public void Work(IList<MyModel> data) 
{ 
    Parallel.ForEach(data, item=>{ 
     DoSomeTask(item); 
    }); 
} 

代わりに...

public void Work(IList<MyModel> data) 
{ 
    Task.WaitAll(data.Select(item=>{ 
     DoSomeTask(item); 
    })); 
} 

を書くことができます。

itemは、コレクションに重複した項目がない限り、各タスクの独立したインスタンスです。入力リストに重複した項目があっても、ConcurrentBagは何も解決しません。

関連する問題