【问题标题】:Locking on field or local variable?锁定字段或局部变量?
【发布时间】:2012-12-21 00:31:26
【问题描述】:

在我阅读了来自 Marc 的 thisan answer 的问题之后......

我有时会看到人们锁定一个本地变量。

这段代码有问题吗?

public void Do()
{
 object  o  = new Object();
 lock (o)
     {
      ...
     }
}

我相信object o = new Object(); 应该是方法之外的Field

由于每个线程都在获取o 的新实例,因此会有多个锁。

我在这里缺少什么?在这种特定情况下,它不应该锁定字段吗?

【问题讨论】:

    标签: c# .net multithreading .net-4.0 locking


    【解决方案1】:

    我认为object o = new Object(); 应该在方法之外作为Field

    由于每个线程都获得了o 的新实例,因此会有 多把锁。

    我在这里缺少什么?在这种特定情况下,它不应该锁定字段吗?

    你的理解是正确的。代码被破坏了。在这个实现中,即使锁处于活动状态,它也不会提供同步,因为它会在不同的对象上。

    来自Microsoft Docs

    当你同步线程访问共享资源时,锁定一个 专用对象实例(例如,私有只读对象 balanceLock = new object();) 或另一个不太可能的实例 被不相关的代码部分用作锁定对象。避免使用 相同的锁对象实例用于不同的共享资源,因为它 可能导致死锁或锁争用。特别是,避免 使用以下作为锁定对象:

    this,因为它可能被调用者用作锁。类型实例,如 这些可能通过 typeof 运算符或反射获得。细绳 实例,包括字符串文字,因为它们可能会被实习。抓住 尽可能短的时间锁定以减少锁定争用。

    【讨论】:

    • 是否应该取决于 lock 内部发生了什么?如果两个线程只是修改本地声明的 List,那么锁定该本地列表变量并在其中添加项目是错误的?
    • @FrankQ。如果列表是在本地声明的,即在方法内部,那么每个线程都将拥有自己的列表,并且锁无论如何都变得毫无意义。我们这里有一个锁,它永远不会有任何竞争者,所以它所做的只是浪费性能并引起混乱。
    【解决方案2】:

    是的。它被打破。

    您希望将静态只读对象作为私有字段进行锁定。正如您所怀疑的那样,您的示例代码每次调用 Do 时都会创建一个新对象,因此锁将没有任何东西可以保留并且根本不起作用。

    private static object syncRoot = new object();
    
    lock (syncRoot) { }
    

    【讨论】:

    • 它不必是静态的。 (除非针对不同的实例)
    • 将其设为静态只读不会损害它,只会保护它(即使它不是必需的)
    • 同意。它不必是静态的。取决于您要保护的内容。
    【解决方案3】:

    每次调用方法时都会创建 o 对象。所以,锁不起作用。我的意思是其他线程不会等待锁没有发出信号并控制该锁控制的资源。通常锁对象是类中的一个私有变量,因此所有方法都查看同一个对象。

    【讨论】:

      【解决方案4】:

      我个人认为没有任何理由使用它,因为lock 只是将oinstance 中的特殊字段设置为信号状态。因此其他线程可以检查该实例的状态,并在此基础上执行lock 语句中的代码或等待释放它。

      每次使用局部变量都会分配一个新实例,因此对于每个线程都可以。

      看不出这有什么意义。

      【讨论】:

        【解决方案5】:

        锁定局部变量,锁定将起作用。锁定全局变量可以生效,同步多线程。

        using System;
                using System.Collections.Generic;
                using System.Linq;
                using System.Text;
                using System.Threading.Tasks;
                using System.Threading;
        
                namespace testLock
                {
                    class Program
                    {
                        public static void Main()
                        {
                            // Start a thread that calls a parameterized static method.
                            for(int i = 0; i< 10;i++)
                            {
                                Thread newThread = new Thread(DoWork);
                                newThread.Start(i);
                            }
        
                            Console.ReadLine();
                        }
        
                        static object gObject= new object();
                        public static void DoWork(object data)
                        {
                            int len = (int)data % 3;
                            object tmp = new object();
                            Console.WriteLine("to lock...... Data='{0}'  sleepTime:{1}", data, len);
                            lock (tmp)//tmp won't work, change tmp to gObject to see different output, which is good locking case)
                            {
                                Console.WriteLine("in lock...... Data='{0}'  sleepTime:{1}", data, len);
        
                                Thread.Sleep(  len* 1000);
                                Console.WriteLine("Static thread procedure. Data='{0}'  sleepTime:{1}", data, len);
                            }
                        }
        
                    }
                }
        
            **Lock temp variable,will output:**
            to lock...... Data='1'  sleepTime:1
            in lock...... Data='1'  sleepTime:1
            to lock...... Data='2'  sleepTime:2
            in lock...... Data='2'  sleepTime:2
            to lock...... Data='0'  sleepTime:0
            in lock...... Data='0'  sleepTime:0
            Static thread procedure. Data='0'  sleepTime:0
            to lock...... Data='3'  sleepTime:0
            in lock...... Data='3'  sleepTime:0
            Static thread procedure. Data='3'  sleepTime:0
            to lock...... Data='4'  sleepTime:1
            in lock...... Data='4'  sleepTime:1
            to lock...... Data='5'  sleepTime:2
            in lock...... Data='5'  sleepTime:2
            to lock...... Data='6'  sleepTime:0
            in lock...... Data='6'  sleepTime:0
            Static thread procedure. Data='6'  sleepTime:0
            to lock...... Data='7'  sleepTime:1
            in lock...... Data='7'  sleepTime:1
            to lock...... Data='8'  sleepTime:2
            in lock...... Data='8'  sleepTime:2
            to lock...... Data='9'  sleepTime:0
            in lock...... Data='9'  sleepTime:0
            Static thread procedure. Data='9'  sleepTime:0
            Static thread procedure. Data='1'  sleepTime:1
            Static thread procedure. Data='4'  sleepTime:1
            Static thread procedure. Data='7'  sleepTime:1
            Static thread procedure. Data='2'  sleepTime:2
            Static thread procedure. Data='5'  sleepTime:2
            Static thread procedure. Data='8'  sleepTime:2
        
            **Then lock gObject, will print:**
            to lock...... Data='0'  sleepTime:0
            in lock...... Data='0'  sleepTime:0
            to lock...... Data='1'  sleepTime:1
            to lock...... Data='2'  sleepTime:2
            Static thread procedure. Data='0'  sleepTime:0
            in lock...... Data='1'  sleepTime:1
            to lock...... Data='3'  sleepTime:0
            to lock...... Data='4'  sleepTime:1
            to lock...... Data='5'  sleepTime:2
            to lock...... Data='6'  sleepTime:0
            to lock...... Data='7'  sleepTime:1
            to lock...... Data='8'  sleepTime:2
            to lock...... Data='9'  sleepTime:0
            Static thread procedure. Data='1'  sleepTime:1
            in lock...... Data='5'  sleepTime:2
            Static thread procedure. Data='5'  sleepTime:2
            in lock...... Data='9'  sleepTime:0
            Static thread procedure. Data='9'  sleepTime:0
            in lock...... Data='2'  sleepTime:2
            Static thread procedure. Data='2'  sleepTime:2
            in lock...... Data='8'  sleepTime:2
            Static thread procedure. Data='8'  sleepTime:2
            in lock...... Data='7'  sleepTime:1
            Static thread procedure. Data='7'  sleepTime:1
            in lock...... Data='4'  sleepTime:1
            Static thread procedure. Data='4'  sleepTime:1
            in lock...... Data='3'  sleepTime:0
            Static thread procedure. Data='3'  sleepTime:0
            in lock...... Data='6'  sleepTime:0
            Static thread procedure. Data='6'  sleepTime:0
        

        【讨论】:

        • C#中没有全局变量。
        • 你是对的,这个例子中的全局变量我的意思是类Program中的静态变量。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-01-08
        • 2012-04-28
        • 1970-01-01
        • 2017-03-04
        • 2013-04-12
        • 1970-01-01
        • 2011-11-26
        相关资源
        最近更新 更多