2

Parallel.For 内の List<> に追加する C# .Net 4 コードがあります。これがスレッドセーフかどうかについての明確な答えが見つかりません。安全でない場合、代替手段は何ですか?

    static List<int> Calculate(List<string[]> numbers)
    {
           List<int> sums = new List<int>();


            Parallel.ForEach(numbers,
            (nums) =>
            {
                int sum = 0;
                for (int i = 0; i < nums.Length; i++)
                     sum += Convert.ToInt32( nums[i]);

                // is this thread safe or not???
                sums.Add(sum);
            });

            sums.Sort();
            return sums;
    }
4

3 に答える 3

12

いいえ、スレッドセーフではありません。スレッドセーフな順序付けられていないコレクションであるConcurrentBag<T>classを探しているかもしれません。MSDN の Thread-Safe Collections documentationで、いくつかの詳細情報とその他のスレッド セーフ コレクションを入手できます。例えば

static List<int> Calculate(List<string[]> numbers)
{
       var sums = new ConcurrentBag<int>();


        Parallel.ForEach(numbers,
        (nums) =>
        {
            int sum = 0;
            for (int i = 0; i < nums.Length; i++)
                 sum += Convert.ToInt32( nums[i]);

            sums.Add(sum);
        });

        var sorted = sums.OrderBy(x => x).ToList();
        return sorted;
}
于 2013-07-10T15:54:45.220 に答える
4

いいえ、ちがいます。

リストは、コレクションが変更されない限り、複数のリーダーを同時にサポートできます。コレクションの列挙は、本質的にスレッドセーフな手順ではありません。列挙が 1 つ以上の書き込みアクセスと競合するまれなケースでは、スレッドの安全性を確保する唯一の方法は、列挙全体でコレクションをロックすることです。読み取りおよび書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

MSDNから

于 2013-07-10T15:55:23.030 に答える
4

メソッドを PLINQ 操作に変換することで、スレッド セーフの問題を回避 (およびパフォーマンスの向上) できます。

static List<int> Calculate(List<string[]> numbers)
{
    return numbers.AsParallel()
                  .Select(nums => nums.Sum(Convert.ToInt32))
                  .OrderBy(i => i)
                  .ToList();
}
于 2013-07-10T16:11:49.837 に答える