为什么“锁定”关键字是对象参数

时间:2019-01-25 07:10:09

标签: c# multithreading synchronization locking

我不会说英语,并且使用翻译。

我想知道何时研究线程同步。

class MainApp
{
    static public int count = 0;
    static private object tLock = new object();

    static void plus()
    {
        for (int i = 0; i < 100; i++)
        {
            lock (tLock)
            {
                count++;
                Console.WriteLine("plus " + count);
                Thread.Sleep(1);
            }
        }
    }

    static void minus()
    {
        for (int i = 0; i < 100; i++)
        {
            lock (tLock)
            {
                count--;
                Console.WriteLine("minus " + count);
                Thread.Sleep(1);
            }
        }
    }

    static void Main()
    {
        Thread t1 = new Thread(new ThreadStart(plus));
        Thread t2 = new Thread(new ThreadStart(minus));

        t1.Start();
        t2.Start();
    }
}

简单线程学习。

静态私有对象tLock = new object();

lock(tLock)<<参数值,为什么要使用对象参数?

2 个答案:

答案 0 :(得分:6)

为什么在lock上有一个对象自变量?

好吧,因为它很方便。

首先,在您的代码示例中显而易见的是,在lock的调用之间需要某种共享状态,以声明代码的两个不同部分是互斥的。如果语法只是lock { }而没有参数,则如下所示:

public void DoSomestuff()
{
    lock
    {
        // Section A
    }
}

public void DoOtherStuff()
{
    lock
    {
        // Section B
    }
}

那么所有锁要么是互斥的,要么仅影响它们各自的代码部分(因此,两个线程可以同时执行A和B部分,但一次只能执行一个线程)。这样会大大降低关键字的有效性。

现在我们确定需要一个共享状态,这个状态应该是什么?我们可以使用一个字符串:

lock ("My Section")
{
    // Section A
}

它可以工作,但有一些缺点:

  1. 您可能会遇到不同库中不同部分名称之间潜在的冲突
  2. 这意味着运行时必须保留一种表来将字符串与锁关联。没什么难的,但这是一些开销

.NET作者改为使用对象参数。这解决了问题1 /,因为您知道除非您愿意,否则另一个库将不会引用您的对象。但这也解决了问题2,因为这允许运行时将锁存储在实际的对象头中。这是一个非常整洁的优化。

答案 1 :(得分:1)

请考虑以下内容(不带锁):

    for (int i = 0; i < 1000; i++)
    {
        count++;
        Console.WriteLine("plus " + count);
        Thread.Sleep(1);
    }

如果两个线程同时运行:

  • 第一个线程向count添加一个,现在为1。
  • 现在第二个线程接管并为count添加一个,现在为2。
  • 第二个线程继续打印plus 2并循环,然后再次向count添加一个,现在为3。
  • 现在,第一个线程接管并打印plus 3,这是不想要的,因为在调用countWriteLine为1。

添加锁定机制(lock)时,开发人员确保代码的一部分为atomic,即按顺序运行而不会中断。

    for (int i = 0; i < 1000; i++)
    {
        lock (tLock)
        {
            count++;
            Console.WriteLine("plus " + count);
            Thread.Sleep(1);
        }
    }

如果在此遵循相同的模式:

  • 第一个线程向count添加一个,现在为1。
  • 现在第二个线程尝试来接管,但必须等到第一个线程释放lock
  • 第一个线程打印plus 1并释放锁。
  • 现在第二个线程可以接管并添加一个线程到count,现在为2。
  • 第一个线程尝试接管,但必须等待第二个线程释放lock
  • 第二个线程打印plus 2并释放锁。

如您所见,增量WriteLine现在是同步操作。

修改

更改问题后:

lock关键字需要一个reference type对象。它不必是object。也可以是classinterfacedelegatedynamicstring

public static string a = string.Empty;
public static void Main()
{
    lock(a)
    {
        Console.WriteLine("Hello World");
    }
}

有关更多信息,请参见documentation