C # Parallel loop local variable thread safe information

My question is a little theoretical. I want to know if a List<object> thread safe if I used Parallel.For this way. See below:

 public static List<uint> AllPrimesParallelAggregated(uint from, uint to) { List<uint> result = new List<uint>(); Parallel.For((int)from, (int)to, () => new List<uint>(), // Local state initializer (i, pls, local) => // Loop body { if (IsPrime((uint)i)) { local.Add((uint)i); } return local; }, local => // Local to global state combiner { lock (result) { result.AddRange(local); } }); return result; } 

Is the local list thread safe? Do I believe data in a result list without data, due to multiple threads, since I have a normal loop?

Note. I am not worried about the order of the list. I want to know about list length and data.

+6
source share
3 answers

Is this solution thread safe? Technically, yes, actually no.

The most understandable thread-safe List (as opposed to a queue or bag) is that the list is safe with respect to order or, more strictly, index, since there is no key except an ascending integer. In a parallel world, this is a kind of meaningless concept when you think about it. This is why the System.Collections.Concurrent namespace contains a ConcurrentBag and a ConcurrentQueue , but not a ConcurrentList .

Since you are asking about thread safety in a list, I assume that your software should generate a list that is in ascending order. If so, no, your solution will not work. Although the code is technically thread safe, threads can end in any order and your result variable stops sorting.

If you want to use parallel computing, you must save your results in a bag, and then, when all the threads have finished, sort the package to create an ordered list. Otherwise, you must perform the calculation sequentially.

And since you should still use the bag, you can use the ConcurrentBag , and then you don’t have to worry about lock{} .

+6
source

The list is not thread safe. but your current algorithm is working. as explained in other answers and comments.

This is a description of localInit of For.Parallel

The delegate <paramref name="localInit"/> is called once for each thread that participates in the loop and returns the initial local state for each of these threads. These initial states are transferred to the first


IMO You add unnecessary complexity within your loop. Instead, I would use a ConcurrentBag . which is thread safe by design.

 ConcurrentBag<uint> result = new ConcurrentBag<uint>(); Parallel.For((long) from, (long) to, (i, PLS) => { if (IsPrime((uint)i)) { result.Add((uint)i); // this is thread safe. don't worry } }); return result.OrderBy(I => I).ToList(); // order if that matters 

See parallel package here

All public and secure ConcurrentBag members are thread safe and can be used from multiple threads at once.

+3
source

A List<T> not thread safe. For how you use it, thread safety is not required. You need thread safety while accessing a resource from multiple threads. You do not do this because you are working on local lists.

At the end, you add the contents of local lists to the result variable. Since you are using lock for this operation, you are not safe inside this block.

So your decision is probably fine.

+2
source

Source: https://habr.com/ru/post/1013785/


All Articles