开发者

C# parallel programming with list - is reading thread-safe?

I'm reading a book about parallel programming an it says that it's not thread save to add elements to list without using lock as result will be unpredictable. For example if we have to add 800 000 elements to list, final result will have less then 800 000 elements.

Now I am wondering if it is thread save to read elements from the list. For example lets say that I have a list BlackListedNumbers

List<int> BlackListedNumbers = new List<int> {10, 50 ....... n}; 
//lets say there is 500 000 elements in the list

and another list Numbers containing 10 000 000 numbers, obviously I'll use parallel.Foreach to complete this task and what I want is Final list contai开发者_开发知识库ning all numbers from Numbers that are not in BlackListedNumbers list

List<int> finalList = new List<int>();
Parallel.ForEach(Numbrs, 
  num =>
    {
      if (!blackListedNumbrs.Contains(num))
      {
        lock (finalList)
        {
          finalList.Add(num);
        }
      }
  });

I know that this is not the most efficient way to get this done but I'm just trying to illustrate the problem.

So my question is: Is it thread save to read result from List blackListedNumbrs and will I get 100% accurate results?


From MSDN:

A List<T> can support multiple readers concurrently, as long as the collection is not modified.

So if you never modify the list, you should be fine.

Note that using a HashSet<int> would be rather more efficient - and HashSet<T> also supports multiple readers1. You can also use Parallel LINQ to make your query sweeter and almost certainly more efficient:

// If you want duplicates in Numbers to still come up as duplicates in the result
HashSet<int> blacklistedSet = new HashSet<int>(blackListedNumbers);
List<int> finalList = Numbers.AsParallel()
                             .Where(x => !blacklistedSet.Contains(x))
                             .ToList();

// Or if you just want a set-based operation:

List<int> finalList = Numbers.AsParallel()
                             .Except(blacklistedSet)
                             .ToList();

Much nicer, and no locking required :)


1 As noted in comments, I don't have any documentation to back this up. But reading from a set doesn't need to modify any shared state, so it at least makes sense...


As long as noone else is writing/adding/deleting blackListedNumbers yes


Read is safe so your code above should work fine, and indeed adding records to the list with multiple threads will cause problems. .NET 4.0 introduced Thread-Safe Colections In your case you can use ConcurrentBag to use multiple threads to add items to the collection.

Here is my example of using it:

var data = new ConcurrentBag<DJVSStatsEv>();

Parallel.ForEach(globalData.ValuationEventsPit, item =>
              {
                   data.Add(new DJVSStatsEv(item.DateYearMonth, item.EventType, eventGroup) {PostVal = item.PostVal, PreVal = item.PreVal, Raised = item.Raised});
             });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜