简体   繁体   中英

Is updating a property for an object in a Parallel.ForEach thread safe?

Public Class Customer
{
   public int CustomerId{get;set;}
   Public string CustomerName{get;set;}
}

public class RunParallel(List<Customer> namelessCustomers)
{
   Parallel.ForEach(namelessCustomers, (customer) =>{
      var customerName = CallAPIToReturnCustomerName(customer.CustomerId);
      customer.CustomerName = customerName
   }
}

Hi is customer.CustomerName=customerName thread safe. What I want is to update the list of customers so that each object get the customers name. if not how can I get something like this to work. Also can you please explain why this would not be thread safe?

Firstly, Strings are immutable , and references are atomic , so that property is thread safe, that's not to say it's immune from stale values and data races - though that doesn't seem to be the case here

Secondly, you are calling an IO workload in parallel.ForEach which is not optimal. Meaning, you are blocking and tying up thread pool threads which could be efficiently offloaded to IO Completion ports. You are likely just better off letting the API call be async , and using Task.WhenAll

Example

public async Task<Customer> CallAPIToReturnCustomerNameAsync(int customerId) 
{
   ///await someThingAsyncHere();
}

...

async Task Process(Customer customer)
{
    customer.CustomerName = await CallAPIToReturnCustomerNameAsync(customer.CustomerId);
}

var tasks = namelessCustomers.Select(Process);
await Task.WhenAll(tasks);

The main dangers are concurrent read/writes or writes/writes. If each object is guaranteed to only be accessed from a single thread this would be threadsafe per default, Ie the list does not have multiple copies of the same customer, and there is no other thread that can access the customer list while the loop is running.

Even if there is concurrent access, this is atomic as long as the type is a reference type, or the value type is smaller than a native integer, as is the case in this example. However, this is only true for a single read/write access, any operation involving multiple operations would not be safe.

Thread safety and concurrency are two approaches that are notable inside two situations: 1- There is one single critical area that concurrent readers/writers can enter. (even in concurrent programming or parallelism) By concurrent programming I mean multi-threading and by parallelism, I mean multi-core programming. 2- Writers cause readers and vise versa. For example, you have to read and check before writing on a single area. Both of the rules above can cause race conditions and should be notable. In your case:

  • You don't have any race, because you are just writing and the sequence is not important.
  • You don't have any race again, because you are writing in several areas and areas (property of different customers) are not shared.

Note: The race condition is not related to the way/stack/language of multi-X programming and you may have this situation in both multi-threading, multi-core programming. So I highly recommend you to double check your code and find critical areas and write/write or write/read moments. And you will find there is no:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM