使用单独的对象进行同步

时间:2012-12-28 13:42:08

标签: c# multithreading synchronization locking

我看到了很多:

object lockObj;
List<string> myStrs;

// ...

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

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

List<string> myStrs;

// ...

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

5 个答案:

答案 0 :(得分:5)

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

如果它是私人会员,那么应该没有问题,但在任何情况下锁定单独的object都是一个好习惯。

有关更详细的答案,请参阅此类似问题: Why is lock(this) {...} bad?

答案 1 :(得分:2)

  

通常,避免锁定公共类型或超出代码控制范围的实例。常见的构造锁(this),lock(typeof(MyType))和lock(“myLock”)违反了这条准则:

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

    最佳做法是定义要锁定的私有对象,或私有静态对象变量以保护所有实例共有的数据。

形成文档lock c#

答案 2 :(得分:0)

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

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

然后,您的实施的线程安全性可能会被破坏。

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

答案 3 :(得分:0)

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

所以,我认为这导致拇指规则/最佳实践,即拥有私人对象,特别是锁定。

我很想知道是否有更多理由出现。

答案 4 :(得分:0)

如果使用列表作为锁定对象,并将其重置为 null ,则锁定(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();
}