C# 确保类是线程安全的,并且只包含属性(任何专门用于此目的的.NET4.0技术?)

C# 确保类是线程安全的,并且只包含属性(任何专门用于此目的的.NET4.0技术?),c#,.net,multithreading,c#-4.0,thread-safety,C#,.net,Multithreading,C# 4.0,Thread Safety,我有一个具有两个属性和两个方法的类。比如下面的例子。(请忽略数据类型或返回类型,这只是一个典型的场景) 我需要确保这个类是线程安全的。我可以在这两种方法中使用lock(obj)作为一种技术使其线程安全,但考虑到以下几点,使其线程安全的最佳技术是什么: 只有两个属性是读取/更新的。因此,不确定在方法内部锁定是否是一种好技术 如果我只是使属性线程安全,而不是方法或类安全,这就足够了吗 还有,有没有办法使整个类线程安全,而不是单个方法或属性?有没有从.NET4.0推荐的锁技术 我只是想知道我是否正确地

我有一个具有两个属性和两个方法的类。比如下面的例子。(请忽略数据类型或返回类型,这只是一个典型的场景)

我需要确保这个类是线程安全的。我可以在这两种方法中使用lock(obj)作为一种技术使其线程安全,但考虑到以下几点,使其线程安全的最佳技术是什么:

  • 只有两个属性是读取/更新的。因此,不确定在方法内部锁定是否是一种好技术

  • 如果我只是使属性线程安全,而不是方法或类安全,这就足够了吗

  • 还有,有没有办法使整个类线程安全,而不是单个方法或属性?有没有从.NET4.0推荐的锁技术

  • 我只是想知道我是否正确地思考了这个问题,或者考虑到这些问题,我把事情复杂化了。非常感谢你帮我弄清楚这一点


    Mani

    一般来说,
    锁定
    可能是最简单的方法

    一个可能更好的选择是使这个类不可变。如果您这样做是为了在创建类后不能更改类中的值,那么在读取这些值时就不必担心了,因为它们是无法修改的

    在这种情况下,可以使用一个接受这两个值的构造函数,并将
    UpdateStock
    更改为更类似于:

    public Stock GetUpdatedStock()
    {
         // Create a new instance here...
         return new Stock(this.FaceValue + DateTime.Now.MilliSecond, this.FaceValue * 100);
    }
    

    编辑:

    现在您已经将FaceValue和Percent设置为静态,您将需要同步。
    可能是这里最简单的选择

    对于单个值,您可能会使用来以原子方式处理更新,但无法对两个值*进行原子更新,这可能是正确执行线程安全性所必需的。在这种情况下,通过
    锁进行同步将解决您的问题


    *注意:如果您将两个值都放在一个类中,并交换整个类实例,则这可能在没有锁的情况下完成,但这可能会带来更多麻烦。

    一般来说,
    锁可能是最简单的方法

    一个可能更好的选择是使这个类不可变。如果您这样做是为了在创建类后不能更改类中的值,那么在读取这些值时就不必担心了,因为它们是无法修改的

    在这种情况下,可以使用一个接受这两个值的构造函数,并将
    UpdateStock
    更改为更类似于:

    public Stock GetUpdatedStock()
    {
         // Create a new instance here...
         return new Stock(this.FaceValue + DateTime.Now.MilliSecond, this.FaceValue * 100);
    }
    

    编辑:

    现在您已经将FaceValue和Percent设置为静态,您将需要同步。
    可能是这里最简单的选择

    对于单个值,您可能会使用来以原子方式处理更新,但无法对两个值*进行原子更新,这可能是正确执行线程安全性所必需的。在这种情况下,通过
    锁进行同步将解决您的问题


    *注意:如果您将两个值都放在一个类中,并交换整个类实例,则这可能在没有锁的情况下完成-但这可能比它的价值要麻烦得多。

    没有使线程安全的银弹解决方案,每个场景都需要它自己的解决方案。最明显的是使用
    ,但在您的示例中,您可以简化并使用
    联锁
    类,并使其成为原子操作:

    public class Stock
    { 
    
        private static int FaceValue {get; set;}
    
        Public void UpdateStock()
        {
           //only a single property to update now
           Interlocked.Increment(FaceValue);
        }
    
        //   method that reads the two properties
        public int[] GetStockQuote()
        {
            var currVal = FaceValue;
            return new int[] { currVal, currVal * 100 };
        }
    
    }
    

    请参见MSDN上的。

    没有银弹解决方案可以确保线程安全,每个场景都需要自己的解决方案。最明显的是使用
    ,但在您的示例中,您可以简化并使用
    联锁
    类,并使其成为原子操作:

    public class Stock
    { 
    
        private static int FaceValue {get; set;}
    
        Public void UpdateStock()
        {
           //only a single property to update now
           Interlocked.Increment(FaceValue);
        }
    
        //   method that reads the two properties
        public int[] GetStockQuote()
        {
            var currVal = FaceValue;
            return new int[] { currVal, currVal * 100 };
        }
    
    }
    

    请参见MSDN上的。

    我编辑了代码,将属性设置为静态,并将FaceValue附加了1。只是想弄清楚我是从哪里来的。可以根据对UpdateStock()方法的调用次数更改属性的值。所以,我不确定我是否可以通过使类不可变来解决这个问题。@Mani-Nope-您仍然可以使您的Stock类对实例不可变,但在更新时您的静态变量将需要一个锁。谢谢。我认为,锁似乎是确保线程安全访问方法的最简单但安全的方法。我会在UpdateStock()和GetStockQuote()中使用lock(obj1)(obj1在两个要锁定的方法中都是同一个对象)。我编辑了代码,将属性设置为静态,并将FaceValue追加1。只是想弄清楚我是从哪里来的。可以根据对UpdateStock()方法的调用次数更改属性的值。所以,我不确定我是否可以通过使类不可变来解决这个问题。@Mani-Nope-您仍然可以使您的Stock类对实例不可变,但在更新时您的静态变量将需要一个锁。谢谢。我认为,锁似乎是确保线程安全访问方法的最简单但安全的方法。我会在UpdateStock()和GetStockQuote()中都使用lock(obj1)(obj1在两个要锁定的方法中都是同一个对象)。如果有人调用
    Stock.UpdateStock()
    当您调用
    GetStockQuote
    时,您可以得到旧的
    FaceValue
    和新的
    Percent
    …噢,谢谢,现在编辑。在我写这篇文章的时候,我开始认为最好建议OP更好地构造它们的类,即同步一个类/结构,而不是一个属性值数组。这是可行的,因为FaceValue是一个Int32,但值得一提的是,对于其他类型,它可能会失败。不过,这不是线程安全的。如果有人调用
    Stock.UpdateStock()
    在调用
    GetStockQuote
    时,可以得到旧的
    FaceValue
    和n