System.Array 的 SetValue/GetValue 方法是线程安全的吗?
我们在办公室进行了一些讨论,但没有得到书面答案:
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 ??
}
}
}
正如您所看到的,每个线程在静态数组中设置一个不同的、唯一的项目。我使用 Reflector 深入研究了代码(并研究了 mscorlib.pdb)。最终有一个调用:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private unsafe extern static void InternalSetValue(void * target, Object value);
没有记录。查看 MSDN 的文档 System.Array
一般来说,以及 SetValue(object, int )
特别是.. 没有关于线程安全的内容(或者也许我遗漏了一些东西)。
正如 Jon Skeet 对类似问题的回答所表达的那样:
我相信如果每个线程只 适用于数组的单独部分, 一切都会好起来的
我正在尝试就这个问题获得 GetValue(int)
和 SetValue(object, int)
的明确答案。有人有文档链接和/或对 InternalSetValue
有更好的了解吗?
We had a little discussion in the office, and got no documented answer:
Is System.Array.SetValue
thread safe?
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 ??
}
}
}
As you can see, every thread sets a different, unique item in the static array. I looked deep into the code using reflector (and looked into mscorlib.pdb). Eventually there's a call to:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private unsafe extern static void InternalSetValue(void * target, Object value);
Which is not documented. Take a look at MSDN's documentation to System.Array
in general, and to SetValue(object, int)
in particular.. Nothing about thread-safety (or maybe I'm missing something).
As it's expressed by Jon Skeet's answer to a similar question:
I believe that if each thread only
works on a separate part of the array,
all will be well
I'm trying to get a definite answer to GetValue(int)
and SetValue(object, int)
regarding this issue. Does someone have a documentation link and/or a better understanding of InternalSetValue
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
MSDN:数组类
它不是线程安全的!
编辑:
一些额外的信息,正常情况下不会调用 Array 类上的 SetValue 方法,仅当通过 IList 接口使用数组时才会调用它。
以下代码:
不会生成对 SetValue() 的调用,而是会生成 OpCodes.Stelem 操作码。
因此,除非使用 IList 引用访问数组,否则 SetValue 方法是否线程安全并不重要。
MSDN: Array class
It's not thread safe!
Edit:
Some extra info, the method SetValue on the Array class is not called in normal circumstances, it's only called when the array is used through the IList interface.
the following code:
Won't generate a call to SetValue(), instead a OpCodes.Stelem opcode will be generated instead.
So it's rather irrelevant if the SetValue method is thread safe or not unless the array is accessed using a IList reference.
在您的示例中,每个线程在数组中设置不同的项目,它将是线程安全的。
把它看作一个冰箱,里面有三罐啤酒,三罐不同的去冰箱挑选他的一罐啤酒,一切都会很顺利,他们会喝一半,放回去,稍后再回来。
然而,无论是在编程中还是在现实生活中,你都不能与三个人分享一罐啤酒。
所以是的:
PS:虽然我没有来源来验证这一点,但碰巧一直使用线程,并且当每个线程读取时我从未遇到过饥饿(?)问题'n 同时写入数组。我在分享“同一罐啤酒”时确实遇到了问题,因此我相信我的答案是正确的,但我希望看到有人验证这一点。
In your example where each thread sets a different item in the array it will be thread safe.
See it as a fridge, there are three cans of beer in there, three different go to the fridge and pick his can of beer, all will go well, they will drink it half-way, put it back and return for it later.
However you can't share 1 can of beer with three people, neither when programming or in real-life.
so yeah:
PS: I have no source to verify this though, but happen to use threads all the time and I never had a starvation(?) problem when each thread reads 'n writes simultaneously in an array. I DO suffer from problems when sharing the 'same can of beer' therefore I believe my answer is correct, but I'd like to see someone verify this.
在您的示例中,对
InternalSetValue(void *, object)
的调用是对三个不同的内存位置进行的。因此,它应该是线程安全的。对这些位置的写入不会渗透到其他位置,即使它们是同一数组的成员。In your example, the calls to
InternalSetValue(void *, object)
are being made to three different memory locations. Therefore, it should be thread-safe. The writes to those locations are not going bleed over into other locations, even if they are members of the same array.