Ron*_*ein 5 c# arrays thread-safety setvalue
我们在办公室进行了一些讨论,没有记录答案:
是System.Array.SetValue线程安全的?
using System;
using System.Text;
using System.Threading;
namespace MyApp
{
class Program
{
private static readonly object[] arr = new object[3];
static void Main(string[] args)
{
string value1 = "hello";
int value2 = 123;
StringBuilder value3 = new StringBuilder();
value3.Append("this");
value3.Append(" is ");
value3.Append("from the StringBuilder");
var states = new object[]
{
new object[] {0, value1},
new object[] {1, value2},
new object[] {2, value3}
};
ThreadPool.QueueUserWorkItem(MySetValue, states[0]);
ThreadPool.QueueUserWorkItem(MySetValue, states[1]);
ThreadPool.QueueUserWorkItem(MySetValue, states[2]);
Thread.Sleep(0);
Console.WriteLine("press enter to continue");
Console.ReadLine();
// print the result
Console.WriteLine("result:");
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine("arr[{0}] = {1}", i, arr[i]);
}
// quit
Console.WriteLine("press enter to quit");
Console.ReadLine();
}
// callback
private static void MySetValue(object state)
{
var args = (object[]) state;
var index = (int)args[0];
var value = args[1];
arr[index] = value; // THREAD-SAFE ??
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,每个线程在静态数组中设置一个不同的唯一项.我使用反射器深入研究了代码(并查看了mscorlib.pdb).最终有一个电话:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private unsafe extern static void InternalSetValue(void * target, Object value);
Run Code Online (Sandbox Code Playgroud)
哪个没有记录.System.Array一般来看一下MSDN的文档SetValue(object, int),特别是..没有关于线程安全的信息(或者我可能缺少某些东西).
正如Jon Skeet对类似问题的回答所表达的那样:
我相信如果每个线程只在阵列的一个单独部分上工作,那么一切都会很好
我试图得到一个明确的答案GetValue(int),并SetValue(object, int)就这个问题.有人有文档链接和/或更好地理解InternalSetValue?
MSDN:数组类
此类型的公共静态(在 Visual Basic 中为共享)成员是线程安全的。不保证任何实例成员都是线程安全的。
此实现不为数组提供同步(线程安全)包装器;但是,基于 Array 的 .NET Framework 类使用 SyncRoot 属性提供其自己的同步版本的集合。
它不是线程安全的!
编辑:
一些额外的信息,正常情况下不会调用 Array 类上的 SetValue 方法,只有通过 IList 接口使用数组时才会调用它。
下面的代码:
int[] arr = ...
arr[i] = value;
Run Code Online (Sandbox Code Playgroud)
不会生成对 SetValue() 的调用,而是会生成 OpCodes.Stelem 操作码。
因此,除非使用 IList 引用访问数组,否则 SetValue 方法是否线程安全并不重要。