[.NET]关于Lock总结_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > [.NET]关于Lock总结

[.NET]关于Lock总结

 2013/7/16 14:49:10  YanZhiwei  博客园  我要评论(0)
  • 摘要:lock关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。lock关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。lock关键字在块的开始处调用Enter,而在块的结尾处调用Exit。通常,应避免锁定public类型,否则实例将超出代码的控制范围。常见的结构lock(this)、lock(typeof(MyType))和lock("myLock"
  • 标签:总结 .net net

lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。

lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。 常见的结构 lock (this)、 lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock(“myLock”) 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。——MSDN

class="csharpcode">        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread t = new Thread(new ParameterizedThreadStart(ProcessWork));
                t.Name = i.ToString();
                t.Start(i);
                threads.Add(t);
            }

        }
        static IList<Thread> threads = new List<Thread>();
        private static readonly object syncRoot = new object();
        static void ProcessWork(object _oNumber)
        {
            //lock (syncRoot)
            //{
            Thread _currentThread = Thread.CurrentThread;
            Console.WriteLine(string.Format("Number:【{0}】,ManagedThreadId:【{1}】-ThreadState:【{2}】.", _oNumber, _currentThread.ManagedThreadId, _currentThread.ThreadState));
            Thread.Sleep(500);
            foreach (Thread t in threads)
            {
                Console.WriteLine(string.Format("ManagedThreadId:【{0}】-ThreadState:【{1}】.", t.ManagedThreadId, t.ThreadState));
            }
            //}
        }

当没有LOCK情况,效果如图:

image

当加了LOCK情况,代码如图:

        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread t = new Thread(new ParameterizedThreadStart(ProcessWork));
                t.Name = i.ToString();
                t.Start(i);
                threads.Add(t);
            }

        }
        static IList<Thread> threads = new List<Thread>();
        private static readonly object syncRoot = new object();
        static void ProcessWork(object _oNumber)
        {
            lock (syncRoot)
            {
                Thread _currentThread = Thread.CurrentThread;
                Console.WriteLine(string.Format("Number:【{0}】,ManagedThreadId:【{1}】-ThreadState:【{2}】.", _oNumber, _currentThread.ManagedThreadId, _currentThread.ThreadState));
                Thread.Sleep(500);
                foreach (Thread t in threads)
                {
                    Console.WriteLine(string.Format("ManagedThreadId:【{0}】-ThreadState:【{1}】.", t.ManagedThreadId, t.ThreadState));
                }
            }
        }

image


提供给 lock 关键字的参数必须为基于引用类型的对象,该对象用来定义锁的范围。锁的范围限定为此函数,因为函数外不存在任何对对象 lockThis 的引用。 如果确实存在此类引用,锁的范围将扩展到该对象。严格地说,提供的对象只是用来唯一地标识由多个线程共享的资源,所以它可以是任意类实例。然而,实际上,此对象通常表示需要进行线程同步的资源。例如,如果一个容器对象将被多个线程使用,则可以将该容器传递给 lock,而 lock 后面的同步代码块将访问该容器。只要其他线程在访问该容器前先锁定该容器,则对该对象的访问将是安全同步的。

通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。 例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。 这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。锁定字符串尤其危险,因为字符串被公共语言运行时 (CLR)“暂留”。这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。因此,最好锁定不会被暂留的私有或受保护成员。某些类提供专门用于锁定的成员。例如, Array 类型提供 SyncRoot。 许多集合类型也提供 SyncRoot。

使用 lock (C#) 关键字通常比直接使用 Monitor 类更可取,一方面是因为 lock 或 SyncLock 更简洁,另一方面是因为lock确保了即使受保护的代码引发异常,也可以释放基础监视器。 这是通过 finally 关键字来实现的,无论是否引发异常它都执行关联的代码块。——MSDN

参考链接:

[Thread] 執行緒同步資源鎖定 – lock / SyncLock

发表评论
用户名: 匿名