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?

Enr*_*one 6 .net c# arrays multithreading thread-safety

Based on my understanding, given a C# array, the act of iterating over the array concurrently from multiple threads is a thread safe operation.

By iterating over the array I mean reading all the positions inside the array by means of a plain old for loop. Each thread is simply reading the content of a memory location inside the array, no one is writing anything so all the threads read the same thing in a consistent manner.

This is a piece of code doing what I wrote above:

public class UselessService 
{
   private static readonly string[] Names = new [] { "bob", "alice" };

   public List<int> DoSomethingUseless()
   {
      var temp = new List<int>();

      for (int i = 0; i < Names.Length; i++) 
      {
        temp.Add(Names[i].Length * 2);
      }

      return temp;
   }
}
Run Code Online (Sandbox Code Playgroud)

So, my understanding is that the method DoSomethingUseless is thread safe and that there is no need to replace the string[] with a thread safe type (like ImmutableArray<string> for instance).

Am I correct ?

Now let's suppose that we have an instance of IEnumerable<T>. We don't know what the underlying object is, we just know that we have an object implementing IEnumerable<T>, so we are able to iterate over it by using the foreach loop.

Based on my understanding, in this scenario there is no guarantee that iterating over this object from multiple threads concurrently is a thread safe operation. Put another way, it is entirely possible that iterating over the IEnumerable<T> instance from different threads at the same time breaks the internal state of the object, so that it becomes corrupted.

Am I correct on this point ?

What about the IEnumerable<T> implementation of the Array class ? Is it thread safe ?

Put another way, is the following code thread safe ? (this is exactly the same code as above, but now the array is iterated by using a foreach loop instead of a for loop)

public class UselessService 
{
   private static readonly string[] Names = new [] { "bob", "alice" };

   public List<int> DoSomethingUseless()
   {
      var temp = new List<int>();

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

      return temp;
   }
}
Run Code Online (Sandbox Code Playgroud)

Is there any reference stating which IEnumerable<T> implementations in the .NET base class library are actually thread safe ?

Gab*_*uci 3

在 C# 中,使用 for 循环迭代数组是线程安全操作吗?

如果您严格谈论从多个线程读取Array,那么对于and以及 Microsoft 编写的每个集合来说,这都是线程安全的List<T>,无论您是否使用fororforeach循环。特别是在你的例子中:

var temp = new List<int>();

foreach (var name in Names)
{
  temp.Add(name.Length * 2);
}
Run Code Online (Sandbox Code Playgroud)

您可以根据需要跨多个线程执行此操作。他们都会Names高兴地读取相同的值。

如果您从另一个线程写入(这不是您的问题,但值得注意)

使用循环迭代Arrayor ,它只会继续读取,并且当您遇到更改的值时,它会很乐意读取它们。List<T>for

foreach循环迭代,那就要看实现了。Array如果循环中的值发生变化foreach,它将继续枚举并为您提供更改后的值。

对于List<T>,这取决于您认为“线程安全”的内容。如果您更关心读取准确的数据,那么它有点“安全”,因为它会在枚举中抛出异常并告诉您集合已更改。但如果你认为抛出异常是不安全的,那么它就不安全。

但值得注意的是,这是一个设计决策List<T>有代码显式地查找更改并抛出异常。设计决策将我们引向下一点:

我们是否可以假设实现的每个IEnumerable集合都可以安全地跨多个线程读取?

大多数情况下是这样,但不能保证线程安全的读取。原因是因为 everyIEnumerable需要一个 的实现IEnumerator,它决定如何遍历集合中的项目。就像任何类一样,您可以在其中做任何您想做的事情,包括非线程安全的事情,例如:

  • 使用静态变量
  • 使用共享缓存读取值
  • 没有做出任何努力来处理集合在枚举过程中发生更改的情况
  • ETC。

您甚至可以做一些奇怪的事情,例如GetEnumerator()每次调用时都返回枚举器的同一个实例。这确实可能会产生一些不可预测的结果。

如果某些东西会导致不可预测的结果,我认为它不是线程安全的。任何这些事情都可能导致不可预测的结果。

您可以查看使用源代码EnumeratorList<T>,因此您可以看到它没有做任何奇怪的事情,这告诉您List<T>从多个线程进行枚举是安全的。