一. 为什么要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. Wordpress制作文章页面single.php

    可以调用的文章内容: 调用文章标题:<?php the_title(); ?> 调用文章内容:<?php the_content(); ?> 调用文章摘要:<?php t ...

  2. Android (二维码)关于java.lang.UnsatisfiedLinkError的小案例

    在许多项目中我们都会用到第三方动态库.so文件,但是往往会引来很多烦恼,比如:Java.lang.UnsatisfiedLinkError - ::-/com.ishow.scan E/Android ...

  3. Velocity模板引擎语法

    Velocity 模板引擎介绍 Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由java ...

  4. jedis例子

    @Test public void testDiscoverNodesAutomatically(){ Set<HostAndPort> jedisClusterNode=new Hash ...

  5. JQuery对象操作支持链式法则源码分析

    JQuery链式法则 何为链式法则?先给出非链式写法的例子 //非链式写法 $("div").css("width", 45px); $("div&q ...

  6. C#窗体 流

    流:(I/O)输入输出流 分类:文件流,内存流,网络流 流的操作一般要放在try catch里面,操作文件网络容易出现异常 命名空间:using system .IO;using system .Te ...

  7. Qt之键盘讲解

    QWSInputMethod详解 注意:这个类不仅仅在嵌入式环境下有效 一个输入法包括了过滤器和可选的图形界面,用来过滤服务器和客户端应用程序之间 的输入事件. 创建自定义的输入法,需要得自QWSIn ...

  8. ASP.NET 管道事件与HttpModule, HttpHandler简单理解

    BeginRequest 指示请求处理开始 AuthenticateRequest 封装请求身份验证过程 AuthorizeRequest 封装检查是否能利用以前缓存的输出页面处理请求的过程 Reso ...

  9. Entity Framework 第十篇 条件查询

    业务类中 我们根据条件来动态的查询 创建IQueryable接口 public IQueryable<TEntity> GetQueryable() { IQueryable<TEn ...

  10. [LeetCode_1] twoSum

    LeetCode: 1. twoSum 题目描述 Given an array of integers, return indices of the two numbers such that the ...