【问题标题】:Using a separate object for synchronisation使用单独的对象进行同步
【发布时间】:2012-12-28 13:42:07
【问题描述】:

我经常看到这个:

object lockObj;
List<string> myStrs;

// ...

lock(lockObj)
{
    myStrs.Add("hello world");
}

为什么要有单独的对象?当然你可以这样做:

List<string> myStrs;

// ...

lock(myStrs)
{
    myStrs.Add("hello world");
}

【问题讨论】:

    标签: c# multithreading synchronization locking


    【解决方案1】:

    仅当myStrs 为public 时直接锁定列表是有问题的,因此也可能被其他调用者锁定,从而可能导致死锁。

    如果是私人成员,那应该没有问题,但是锁定一个单独的object无论如何都是一个好习惯。

    查看这个类似的问题以获得更详细的答案: Why is lock(this) {...} bad?

    【讨论】:

      【解决方案2】:

      一般来说,避免锁定公共类型或超出代码控制范围的实例。常见的构造 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反了这个准则:

      1. 如果实例可以公开访问,则锁定(this)是一个问题。
      2. lock (typeof (MyType)) 如果 MyType 可公开访问,则会出现问题。
      3. lock(“myLock”) 是一个问题,因为进程中使用相同字符串的任何其他代码都将共享相同的锁。

      最佳实践是定义一个私有对象来锁定,或者定义一个私有静态对象变量来保护所有实例共有的数据。

      形成文档lock c#

      【讨论】:

      • +1 - 这些是大问题 - 主要是“如果其他人可以看到我锁定的东西,其他人可以抢走我的锁”这一点;使用这里提到的字符串是双重危险的,因为字符串通常是内部的,这样所有相等的字符串实际上都是同一个对象。
      【解决方案3】:

      我们的想法是始终锁定只能由我们正在查看的代码访问的私有成员。而当我们锁定我们无法控制的成员(如公共成员或类似成员)时,很可能代码的其他部分已经可以锁定。这可能会导致意外的阻塞行为。

      所以,我认为这导致了经验法则/拥有私有对象的最佳实践,尤其是用于锁定。

      我很想看看是否还有更多原因。

      【讨论】:

        【解决方案4】:

        您的字符串列表是用于内部实现细节的列表。

        如果您更改实现以重新初始化字符串列表的方式,第二个版本的问题可能会出现。

        那么你的实现的线程安全可能会被破坏。

        所以最好使用单独的对象进行同步,并将该对象声明为只读。

        【讨论】:

          【解决方案5】:

          如果您使用列表作为锁定对象,并将其重置为 null,则 lock(myStringList) 将抛出 ArgumentNullException。下面是控制台应用程序的简单测试代码。

            private static IList<string> mystringList = new List<string>();
          
          static void Main(string[] args)
          {
              new Thread(() =>
                  {
                      try
                      {
          
                          while (true)
                          {
                              //Acquire the lock
                              lock (mystringList)
                              {
                                  //Do something with the data
                                  Thread.Sleep(100);
                                  Console.WriteLine("Lock acquired");
                              }
                          }
                      }
                      catch (Exception exception)
                      {
                          Console.WriteLine("Exception: " +exception.Message);
                      }
                  }).Start();
          
              new Thread(() =>
                  {
                      //Suppose we do something
                      Thread.Sleep(1000);
          
                      //And by some how reset the list to null
                      mystringList = null;
          
                  }).Start();
          
              Console.ReadLine();
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多