代码之家  ›  专栏  ›  技术社区  ›  Ron Klein Noa Kuperberg

System.Array的SetValue/GetValue方法是线程安全的吗?

  •  5
  • Ron Klein Noa Kuperberg  · 技术社区  · 15 年前

    我们在办公室里进行了一次小讨论,但没有得到书面答复:

    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); 
    

    System.Array 一般而言,以及 SetValue(object, int) 特别地。。与线程安全无关(或者可能我遗漏了一些东西)。

    similar question :

    我相信只要每一根线 在阵列的一个单独部分上工作, 一切都会好起来的

    我正试图得到一个明确的答案 GetValue(int) 设置值(对象,int) 关于这个问题。是否有人有文档链接和/或更好地理解 InternalSetValue ?

    3 回复  |  直到 8 年前
        1
  •  3
  •   Pop Catalin    15 年前

    MSDN: Array class

    公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 保证线程安全。

    此实现不提供 阵列;然而,.NET框架 基于数组的类提供了它们的 自己的同步版本的 财产。

    一些额外的信息,数组类上的方法SetValue在正常情况下不被调用,它只在通过IList接口使用数组时被调用。

    以下代码:

    int[] arr = ...
    arr[i] = value;
    

    不会生成对SetValue()的调用,而是生成一个操作码。将生成Stelem操作码。

    因此,除非使用IList引用访问数组,否则SetValue方法是否是线程安全的就无关紧要了。

        2
  •  0
  •   Pieter888    15 年前

    把它看成一个冰箱,里面有三罐啤酒,三种不同的啤酒。去冰箱拿他的啤酒罐,一切都会好起来的,他们会喝一半,放回去,然后回来拿。

    然而,无论是在编程还是在现实生活中,你都不能和三个人分享一罐啤酒。

    所以是的:

    PS:虽然我没有源代码来验证这一点,但碰巧总是使用线程,而且当每个线程在一个数组中同时读n写时,我从未遇到过饥饿(?)问题。我确实在分享“同一罐啤酒”时遇到问题,因此我相信我的答案是正确的,但我希望有人能证实这一点。

        3
  •  0
  •   Jeffrey L Whitledge    15 年前

    在您的示例中,调用 InternalSetValue(void *, object)