Are the SetValue/GetValue methods of System.Array thread-safe?
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开发者_StackOverflow 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
?
MSDN: Array class
Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
This implementation does not provide a synchronized (thread safe) wrapper for an Array; however, .NET Framework classes based on Array provide their own synchronized version of the collection using the SyncRoot property.
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:
int[] arr = ...
arr[i] = value;
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.
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:
if each thread only works on a separate part of the array, all will be well
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.
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.
精彩评论