Is iterating over an array with a for loop a thread safe operation in C# ? What about iterating an IEnumerable<T> with a foreach loop?

Is iterating over an array with a for loop a thread safe operation in C# ?

If you're strictly talking about reading from multiple threads, that will be thread safe for Array and List<T> and just about every collection written by Microsoft, regardless of if you're using a for or foreach loop. Especially in the example you have:

var temp = new List<int>();

foreach (var name in Names)
{
  temp.Add(name.Length * 2);
}

You can do that across as many threads as you want. They'll all read the same values from Names happily.

If you write to it from another thread (this wasn't your question, but it's worth noting)

Iterating over an Array or List<T> with a for loop, it'll just keep reading, and it'll happily read the changed values as you come across them.

Iterating with a foreach loop, then it depends on the implementation. If a value in an Array changes part way through a foreach loop, it will just keep enumerating and give you the changed values.

With List<T>, it depends what you consider "thread safe". If you are more concerned with reading accurate data, then it kind of is "safe" since it will throw an exception mid-enumeration and tell you that the collection changed. But if you consider throwing an exception to be not safe, then it's not safe.

But it's worth noting that this is a design decision in List<T>, there is code that explicitly looks for changes and throws an exception. Design decisions brings us to the next point:

Can we assume that every collection that implements IEnumerable is safe to read across multiple threads?

In most cases it will be, but thread-safe reading is not guaranteed. The reason is because every IEnumerable requires an implementation of IEnumerator, which decides how to traverse the items in the collection. And just like any class, you can do anything you want in there, including non-thread-safe things like:

  • Using static variables
  • Using a shared cache for reading values
  • Not making any effort to handle cases where the collection changes mid-enumeration
  • etc.

You could even do something weird like make GetEnumerator() return the same instance of your enumerator every time its called. That could really make for some unpredictable results.

I consider something to not be thread safe if it can result in unpredictable results. Any of those things could cause unpredictable results.

You can see the source code for the Enumerator that List<T> uses, so you can see that it doesn't do any of that weird stuff, which tells you that enumerating List<T> from multiple threads is safe.