一. 为什么要lock,lock了什么?

当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA){codeB} 。

lock(objectA){codeB} 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
1. objectA被lock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
2. lock以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA。
3. 执行完codeB之后释放objectA,并且codeB可以被其他线程访问。

二. lock(this)怎么了?

我们看一个例子:

  1. using System;
  2. using System.Threading;
  3. namespace Namespace1
  4. {
  5. class C1
  6. {
  7. private bool deadlocked = true;
  8. //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
  9. public void LockMe(object o)
  10. {
  11. lock (this)
  12. {
  13. while(deadlocked)
  14. {
  15. deadlocked = (bool)o;
  16. Console.WriteLine("Foo: I am locked :(");
  17. Thread.Sleep(500);
  18. }
  19. }
  20. }
  21. //所有线程都可以同时访问的方法
  22. public void DoNotLockMe()
  23. {
  24. Console.WriteLine("I am not locked :)");
  25. }
  26. }
  27. class Program
  28. {
  29. static void Main(string[] args)
  30. {
  31. C1 c1 = new C1();
  32. //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
  33. Thread t1 = new Thread(c1.LockMe);
  34. t1.Start(true);
  35. Thread.Sleep(100);
  36. //在主线程中lock c1
  37. lock (c1)
  38. {
  39. //调用没有被lock的方法
  40. c1.DoNotLockMe();
  41. //调用被lock的方法,并试图将deadlock解除
  42. c1.LockMe(false);
  43. }
  44. }
  45. }

复制代码

在t1线程中,LockMe调用了lock(this), 也就是Main函数中的c1,这时候在主线程中调用lock(c1)时,必须要等待t1中的lock块执行完毕之后才能访问c1,即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。

lock 是锁定lock里面的代码段,保证代码段不会被同时执行,而不是锁定lock(c1) 的c1,c1.DoNotLockMe()里面不执行到lock(this)里面的代码,所以不会有影响,至于为什么第一段代码中的方法不执行,是因为主程序那里有一个lock(c1),c1对象在前面已经被申请了互斥锁,所以主程序lock里面代码,需要等待支线程解开c1的互斥锁,所以一直不执行。如果把c1.DoNotLockMe()放在lock(c1)前面, 就会被执行

但是正常情况下都不会lock(this) 而以下面的形式

  1. class C1
  2. {
  3. private bool deadlocked = true;
  4. private object locker = new object();
  5. //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
  6. public void LockMe(object o)
  7. {
  8. lock (locker)
  9. {
  10. while(deadlocked)
  11. {
  12. deadlocked = (bool)o;
  13. Console.WriteLine("Foo: I am locked :(");
  14. Thread.Sleep(500);
  15. }
  16. }
  17. }
  18. //所有线程都可以同时访问的方法
  19. public void DoNotLockMe()
  20. {
  21. Console.WriteLine("I am not locked :)");
  22. }
  23. }

C# lock的更多相关文章

  1. C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEvent

    看下组织结构: System.Object System.MarshalByRefObject System.Threading.WaitHandle System.Threading.Mutex S ...

  2. 多线程同步工具——Lock

    本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...

  3. java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)

    一.Condition 类 在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.c ...

  4. InnoDB:Lock & Transaction

    InnoDB 是一个支持事务的Engine,要保证事务ACID,必然会用到Lock.就像在Java编程一下,要保证数据的线程安全性,必然会用到Lock.了解Lock,Transaction可以帮助sq ...

  5. 使用四元数解决万向节锁(Gimbal Lock)问题

    问题 使用四元数可以解决万向节锁的问题,但是我在实际使用中出现问题:我设计了一个程序,显示一个三维物体,用户可以输入绕zyx三个轴进行旋转的指令,物体进行相应的转动. 由于用户输入的是绕三个轴旋转的角 ...

  6. 万向节锁(Gimbal Lock)的理解

    [TOC] 结论 我直接抛出结论: Gimbal Lock 产生的原因不是欧拉角也不是旋转顺序,而是我們的思维方式和程序的执行逻辑没有对应,也就是说是我们的观念导致这个情况的发生. 他人解释 首先我们 ...

  7. 在多线程编程中lock(string){...}隐藏的机关

    常见误用场景:在订单支付环节中,为了防止用户不小心多次点击支付按钮而导致的订单重复支付问题,我们用 lock(订单号) 来保证对该订单的操作同时只允许一个线程执行. 这样的想法很好,至少比 lock( ...

  8. 谈谈 Lock

    上来先看MSDN关于lock的叙述: lock  关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁.  下面的示例包含一个 lock 语句. lock  关键字可确保当一 ...

  9. LOCK TABLES和UNLOCK TABLES与Transactions的交互

    LOCK TABLES对事务不安全,并且在试图锁定表之前隐式提交任何活动事务. UNLOCK TABLES只有在LOCK TABLES已经获取到表锁时,会隐式提交任何活动事务.对于下面的一组语句,UN ...

  10. SQL 性能调优中可参考的几类Lock Wait

    在我们的系统出现性能问题时,往往避不开调查各种类型 Lock Wait,如Row Lock Wait.Page Lock Wait.Page IO Latch Wait等.从中找出可能的异常等待,为性 ...

随机推荐

  1. 周记:Linux下C编程

    也啥都没干,计划一个都没干.吼吼-- 周六去看[21天学通Linux_C编程]笔记: 突然都对这本书没信心了.刚开始,就出现的不满如下:1.创建vim启动器时候,类型要选择[终端下的应用程序]没说,虽 ...

  2. iOS下Html页面中input获取焦点弹出键盘时挡住input解决方案—scrollIntoView()

    问题描述 iOS系统下,移动web页面,inpu获取焦点弹出系统虚拟键盘时,偶尔会出现挡住input的情况,尽管概率不大,但是十分影响用户体验. 问题重现 原始页面:页面中有header.main.f ...

  3. 基于VirtualBox的多重载入

    问题描述 这个问题要追溯到中秋之前,也就是写第一周博客的时候,当时我用的还是虚拟机上的ubuntu:当时我的ubuntu不是最新版,所以有提示升级,你懂的,我升了(因为时间有点久,我先去吃了个饭):等 ...

  4. openfire及xmpp简单介绍

    一.oprenfire 1.openfire是采用Java开发,开源的实时协作(RTC)服务器基于XMPP(Jabber)协议.可以使用它轻易的构建高效率的即时通信服务器. 2.Openfire安装和 ...

  5. elasticsearch使用操作部分

    本片文章记录了elasticsearch概念.特点.集群.插件.API使用方法. 1.elasticsearch的概念及特点.概念:elasticsearch是一个基于lucene的搜索服务器.luc ...

  6. MVC控制器常用方法返回类型

    控制器的常用方法 using System; using System.Collections.Generic; using System.Linq; using System.Web; using ...

  7. AngularJS Best Practices: pretty urls

    By default, AngularJS will route URLs with a hashtag. For example: http://example.com/ http://exampl ...

  8. Java Servlet(六):HttpServlet实现原理(jdk7+tomcat7+eclipse)

    本篇记录了HttpServlet的实现过程,主要讲述了如何依赖Servlet,GenericServlet实现的原理. HttpServlet实现过程:1.是一个Servlet,继承自GenericS ...

  9. Oracle12c:安装后新建用户及其默认表空间,并创建表测试

    环境: 操作系统:Windows Server2008 R2 X64 Oracle版本:12c 如何安装? -- oracle 12c在oracle linux 6.6 x64上的安装 -- Wind ...

  10. CentOS 升级PHP

    wget http://download.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm wget http://rpm ...