代码之家  ›  专栏  ›  技术社区  ›  xsl Fredrik Hedblad

获取和设置简单的静态属性线程安全吗?[副本]

  •  10
  • xsl Fredrik Hedblad  · 技术社区  · 14 年前

    可能重复:
    Are C# auto-implemented static properties thread-safe?

    static class Shared
    {
        public static string[] Values { get; set; }
    }
    

    许多读者线程读取 Values 周期性地使用字符串数组,而一个编写器会不时地使用setter用一个新值替换整个数组。我需要用电脑吗 ReaderWriterLock 或者这是C#会自动处理的东西?

    编辑:在我的例子中,唯一需要的“线程安全”是:当编写器替换数组,而读取器正在搜索一个值时,不会发生任何不好的事情。我不在乎读者是否会立即使用新值,只要他们将来会使用它

    6 回复  |  直到 7 年前
        1
  •  11
  •   Jeffrey L Whitledge    14 年前

    此用途是线程安全的:

    string[] localValues = Shared.Values;
    for (int index = 0; index < localValues.length; index++)
        ProcessValues(localValues[index]);
    

    此使用不是线程安全的,可能会导致越界异常:

    for (int index = 0; index < Shared.Values.Length; index++)
        ProcessValues(Shared.Values[index]);
    

    static class Shared   
    {
        private static string[] values;   
        public static string[] GetValues() { return values; }
        public static void SetValues(string[] values) { Shared.values = values; }
    }
    

    当然,用户仍然可以将GetValues()放在循环中,这也会很糟糕,但至少它显然很糟糕。

    static class Shared
    {
        private static string[] values;
        public static string[] GetValues()
        {
            string[] currentValues = values;
            if (currentValues != null)
                return (string[])currentValues.Clone();
            else
                return null;
        }
        public static void SetValues(string[] values)
        {
            Shared.values = values;
        }
    }
    
        2
  •  9
  •   Jon Skeet    14 年前

    没有任何额外的保护,就没有 保证 一条阅读线索 曾经 查看新值。在实践中,只要阅读线索是做任何有意义的事情,它

    如果你成功了 volatile ,我相信即使这种危险也被消除了-但是无锁编程通常很难推理。当然,这意味着放弃它作为自动实现的属性。

        3
  •  6
  •   LukeH    14 年前

    read和replacement保证是原子的,但是不能保证在write之后的read必然会读取新的值。

    现有代码不会有什么不好的情况发生(例如,读取错误),但是不能保证您的读者会这样做 曾经 查看新值。例如,旧引用有可能(尽管可能不太可能)永远缓存在寄存器中。

        4
  •  2
  •   James Gaunt    14 年前

    这不是线程安全的。是的,你需要用锁。

        5
  •  2
  •   Mike    14 年前

    ReaderWriterLockSlim -效率比 ReaderWriteLock .

    static class Shared
    {
        private static ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
        private static string[] _values;
    
        public static string[] Values 
        {
            get
            {
                _rwLock.EnterReadLock();
                try
                {
                    return _values;
                }
                finally
                {
                    _rwLock.ExitReadLock();
                }
            }
            set
            {
                _rwLock.EnterWriteLock();
                try
                {
                    _values = value;
                }
                finally
                {
                    _rwLock.ExitWriteLock();
                }
            }
        }
    }
    
        6
  •  1
  •   tc.    14 年前

    Java theory and practice: Fixing the Java Memory Model, Part 2 ):

    • 易失性读/写也是内存障碍。
    • final 字段在构造函数外部完全初始化。

    后者是一个有趣的例子:你曾经能够 foo = new String(new char[]{'a','b','c'}); 在一个线程和 foo = "123"; System.out.println(foo) 在另一个线程中,并打印空字符串,因为无法保证对foo的final字段的写入将发生在对foo的写入之前。