一个线程可以更改对数组的引用,而另一个线程正在迭代它

时间:2016-05-17 13:21:18

标签: c# arrays multithreading

我有一个静态数组变量,由两个线程共享。

我想了解如果我将数组变量分配给Thread1中的另一个数组对象,而Thread2迭代数组时会发生什么。

在主题1中

MyStaticClass.MyArray = SomeOtherArray

在线程2中:

for (int i = 0; i < MyStaticClass.MyArray.length; i++) 
{ 
    //do something with the i'th element
}

4 个答案:

答案 0 :(得分:1)

要防止这种情况,您需要使用锁来锁定关键部分。基本上将您的itteration包装在一个锁中将阻止另一个线程在处理它时覆盖该数组

  

lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区。如果另一个线程试图输入一个锁定的代码,它将等待,阻塞,直到该对象被释放。

https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

答案 1 :(得分:1)

假设MyStaticClass.MyArray只是一个字段或简单属性。

肯定会发生任何好的或可预测的事情。

我说最有可能的是:

  • 循环可以读取旧数组的一半,然后从新数组中读取
  • 当您访问[i]
  • 时,新数组可能会比最后一个数组更短
  • 线程2实际上可能完全忽略对数组的更改!更糟糕的是,Release版本中的这种行为可能与Debug有所不同。

最后一种情况是由于编译器优化和/或内存模型在.net(以及Java BTW等其他语言)中的工作方式。有一个完整的关键字可以解决此问题(volatilehttp://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

答案 2 :(得分:1)

每次迭代都会评估for循环中的条件。因此,如果另一个线程更改MyStaticClass.MyArray中的引用,则在下一次迭代中使用此新引用。

例如,此代码:

int[] a = {1,2,3,4,5};
int[] b =  {10, 20, 30, 40, 50, 60, 70};

for (int i = 0; i < a.Length; i++)
{
     Console.WriteLine(a[i]);
     a = b;
}

给出了这个输出:

1
20
30
40
50
60
70

为避免这种情况,您可以使用foreach

foreach(int c in a)
{
    Console.WriteLine(c);
    a = b;
}

给出:

1
2
3
4
5

因为foreach已翻译,因此它会调用a.GetEnumerator()一次,然后使用此枚举器(MoveNext()Current)进行所有迭代,而不是访问a试。

答案 3 :(得分:0)

除了线程2之外,在某些时候开始处理新阵列而不是旧阵列将没有任何后果。当这种情况发生时或多或少是随机的,正如韦斯顿在评论中写道的那样,它甚至可能永远都不会发生。

如果新数组的元素少于旧数组,则可以(但不必)导致运行时异常。