【问题标题】:Lock in properties, good approach?锁定属性,好方法?
【发布时间】:2010-12-09 09:41:18
【问题描述】:

在我的多线程应用程序中,我使用了一些可以被多个实例同时更改的变量。这很奇怪,但它工作得很好,没有任何问题..但我当然需要让它成为线程安全的。我只是从锁开始,所以我很欣赏你的建议:

当客户端连接时,会创建类 Client,其中每个 Client 都有自己的“A”变量。

有时,客户端会这样调用方法:

Client selectedClient SelectOtherClientClassByID(sentID);

selectedClient.A=5;

即使有 5 个类同时执行(线程池),到目前为止也没有问题,但我在想如何为 A 属性添加锁?

喜欢:

A {
    get { return mA; }
    set {
        // use lock here for settting A to some value
    }    
}

可以吗?

【问题讨论】:

    标签: c# winforms multithreading


    【解决方案1】:

    您需要在获取和设置中都使用锁。这个锁必须是同一个对象。例如:

    private object mylock = new object();
    
    public int A {
    
      get {
        int result;
        lock(mylock) {
        result = mA; 
        }
        return result;
      } 
    
      set { 
         lock(mylock) { 
            mA = value; 
         }
      }
    }
    

    【讨论】:

    • 谢谢...顺便说一句,因为它可能会在其他班级的阅读过程中发生变化?
    • 锁定它不是一个好主意,因为它可以从类型外部访问。
    • 设置时可能会发生变化。锁充当屏障,在锁所有者释放锁之前阻止任何其他操作。
    • @Brian,我同意。对我的代码进行了更改。只是在演示。
    • 对不起,我参加了会议,_NT,请问您的代码在您更改之前看起来如何,我的意思是 Brian 提到的问题是什么?我喜欢尽可能多地学习:)
    【解决方案2】:

    锁定对访问器内部属性的访问可能会导致虚假结果。例如,看下面的代码:

    class C {
        private object mylock = new object();
    
        public int A {
    
          get {
            int result;
            lock(mylock) {
            result = mA; 
            }
            return result;
          } 
    
          set { 
             lock(mylock) { 
                mA = value; 
             }
          }
        }
    }
    C obj = new C;
    C.A++;
    

    (是的,我从第一个答案中复制了它) 这里有一个比赛条件!操作“C.A++”实际上需要对 A 进行两次单独的访问,一次获取值,另一次设置更新的值。没有什么可以确保这两个访问将一起执行,而无需在它们之间进行上下文切换。竞争条件的经典场景!

    所以,小心!将锁放在访问器中不是一个好主意,应该显式获取锁,就像前面的答案所暗示的那样(尽管它不必与 SyncRoots 一起,任何对象都可以)

    【讨论】:

    • 您的意思是手动将锁定对象添加到代码中的所有调用?我想到目前为止,我的代码中至少有 20 次阅读和 15 次写作。
    • 为此,您需要扩展锁定以覆盖整个关键区域。你不会做 A++。
    • NT:我可能不太了解你。我有大约 15 种方法,在不同的实例上使用该变量进行不同的操作。我不确定你的意思是扩大锁。因此,如果我以上所有内容都正确阅读,属性锁就不好了
    • @Petr:我将之前的评论指向 ilial。至于您的评论,您需要确定它们是否具有共同的同步对象。在这种情况下,您应该使用单个锁。如果您不熟悉这一切,请查看这个有趣的链接:codeproject.com/KB/threads/…
    【解决方案3】:

    当您只需要设置一个属性时,这是非常罕见的。更多时候selectedClient.A = 5 将成为更大逻辑操作的一部分,其中涉及多个分配/评估/等。在整个操作过程中,您更希望selectedClient 处于一致状态,而不是引入死锁/竞争条件。因此,最好在 Client 类中公开 SyncRoot 属性并从调用代码中锁定它:

    Client selectedClient = GetClient(...);
    
    lock(selectedClient.SyncRoot)
    {
        selectedClient.A = 5;
        selectedClient.B = selectedClient.A * 54;
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-04
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多