如果在添加元素时我不打算从列表中读取,是否有必要在向其添加元素之前锁定C#列表?

时间:2012-05-01 07:07:47

标签: c# multithreading locking

这是一个MWE:

Func<Int32, Boolean> MyFunc = (s) => {
    var res = false;
    // Insert function logic to modify the value to res
    return res;
};
var Result = new List<Int32> ();
var LockObj = new Object ();
ParallelEnumerable.Range (1, 100000)
    .ForAll (s => {
        if (MyFunc (s)) {
            lock (LockObj) { // IS THIS NECESSARY?
                Result.Add (s);
            } // End lock
        }
    });

这就是情况归结为。如果我在ParallelEnumerable语句完成执行之前不打算查询它,我是否正确认为我不需要锁定Result?

请注意:我知道MWE可以通过“Where”子句更好地解决,如下所示:

ParallelEnumerable.Range (1, 100000)
    .Where (s => MyFunc (s));

但由于MWE中不明显的原因,无法做到这一点。

修改

感谢所有回答的人。还要感谢您的评论。我已经纠正了董某发现的错误。

4 个答案:

答案 0 :(得分:4)

是的,您必须lock。 Parallel.For将导致并发调用Add()

旁注:

//var Result = new List<Int32> ();
var Result = new List<Int32> (100000);
ParallelEnumerable.Range (1, 100000)

将使这更有效率。增长不足也意味着lock上的争用减少。

答案 1 :(得分:3)

添加到通用列表不是线程安全的。阻止是一种可能性。您还可以使用im .Net 4.0中引入的其中一种线程安全集合类型

请查看Parallel For Loop - Problems when adding to a List了解更多

答案 2 :(得分:2)

您可以通过选择其中一个现有并行集合来消除批次争用:

ConcurrentBag<int> bag=new ConcurrentBag<int>();
ParallelEnumerable.Range(0,10000).ForAll(s => {if(MyFunc(s)) bag.Add(s);});

答案 3 :(得分:0)

使用Semaphore.it将管理对共享资源的访问(在您的案例中为公共列表)。