本文为转载 。。

一. 为什么要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)怎么了?

我们看一个例子:

using System;
using System.Threading;
namespace Namespace1
{
class C1
{
private bool deadlocked = true;
//这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
public void LockMe(object o)
{
lock (this)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("Foo: I am locked :(");
Thread.Sleep();
}
}
}
//所有线程都可以同时访问的方法
public void DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}
class Program
{
static void Main(string[] args)
{
C1 c1 = new C1();
//在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
Thread t1 = new Thread(c1.LockMe);
t1.Start(true);
Thread.Sleep();
//在主线程中lock c1
lock (c1)
{
//调用没有被lock的方法
c1.DoNotLockMe();
//调用被lock的方法,并试图将deadlock解除
c1.LockMe(false);
}
}
}

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

把C1的代码稍作改动:

    class C1
{
private bool deadlocked = true;
private object locker = new object();
//这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
public void LockMe(object o)
{
lock (locker)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("Foo: I am locked :(");
Thread.Sleep();
}
}
}
//所有线程都可以同时访问的方法
public void DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}

这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问;LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。

关键点:
1. lock(this)的缺点就是在一个线程(例如本例的t1)通过执行该类的某个使用"lock(this)"的方法(例如本例的LockMe())锁定某对象之后, 导致整个对象无法被其他线程(例如本例的主线程)访问 - 因为很多人在其他线程(例如本例的主线程)中使用该类的时候会使用类似lock(c1)的代码。
2. 锁定的不仅仅是lock段里的代码,锁本身也是线程安全的。
3. 我们应该使用不影响其他操作的私有对象作为locker。
4. 在使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)。

C# 理解lock的更多相关文章

  1. [转]C# 理解lock

    原文:http://www.cnblogs.com/apsnet/archive/2012/07/08/2581475.html 一. 为什么要lock,lock了什么? 当我们使用线程的时候,效率最 ...

  2. 带你理解Lock锁原理

    同样是锁,先说说synchronized和lock的区别: synchronized是java关键字,是用c++实现的:而lock是用java类,用java可以实现 synchronized可以锁住代 ...

  3. 多线程锁--怎么理解Condition

    在java.util.concurrent包中,有两个很特殊的工具类,Condition和ReentrantLock,使用过的人都知道,ReentrantLock(重入锁)是jdk的concurren ...

  4. C#中的lock关键字有何作用

    作为C#的程序员来说,在遇到线程同步的需求时最常用的就是lock关键字.但如何正确并有效地使用lock,却是能否高效地达到同步要求的关键.正因为如此,程序员需要完全理解lock究竟为程序做了什么. 所 ...

  5. 深入理解ReentrantLock

    在Java中通常实现锁有两种方式,一种是synchronized关键字,另一种是Lock.二者其实并没有什么必然联系,但是各有各的特点,在使用中可以进行取舍的使用.首先我们先对比下两者. 实现: 首先 ...

  6. 扯扯python的多线程的同步锁 Lock RLock Semaphore Event Condition

    我想大家都知道python的gil限制,记得刚玩python那会,知道了有pypy和Cpython这样的解释器,当时听说是很猛,也就意味肯定是突破了gil的限制,最后经过多方面测试才知道,还是那德行… ...

  7. 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

    欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...

  8. python redis自带门神 lock 方法

    redis 支持的数据结构比较丰富,自制一个锁也很方便,所以极少提到其原生锁的方法.但是在单机版redis的使用时,自带锁的使用还是非常方便的.自己有车还打啥滴滴顺风车是吧,本篇主要介绍redis-p ...

  9. 【java并发编程】Lock & Condition 协调同步生产消费

    一.协调生产/消费的需求 本文内容主要想向大家介绍一下Lock结合Condition的使用方法,为了更好的理解Lock锁与Condition锁信号,我们来手写一个ArrayBlockingQueue. ...

随机推荐

  1. 通过代码设置textview颜色

    Resources resource = (Resources) this.getResources();   ColorStateList csl = (ColorStateList) resour ...

  2. UVa 442 矩阵链乘(栈)

    Input Specification Input consists of two parts: a list of matrices and a list of expressions. The f ...

  3. linux网络故障解决方法

    一.检测工具 tcpdump:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的“头”完全截获 ...

  4. kuangbin_UnionFind B (POJ 1611)

    过程是模板 merge完后扫一下几个跟0同祖先节点就是答案了 #include <iostream> #include <string> #include <cstdio ...

  5. 使用PHP+ajax打造聊天室应用

    方法1.  comet http://www.xiumu.org/technology/the-php-notes-comet-long-connection-instance.shtml  这篇文章 ...

  6. IE下必须点击一下页面空白的地方才可以激活onchange事件

    checkbox在IE下必须点击一下页面空白的地方才可以激活onchange事件. 解决办法把onchange换成onclick

  7. wikioi 1204 寻找子串位置

    /*======================================================================== 1204 寻找子串位置 题目描述 Descript ...

  8. VC ++ MFC activex 控件获取连接的VPN 信息

    vc++  MFC 进行activex  控件的开发步骤就不用多写了,只是简单的说明一下方法,以及具体的代码: 使用的类库是 windows 系统的 rasapi32.dll 记住需要添加的头文件如下 ...

  9. CSQuery 简单测试

    1. 使用环境 vs2010  ,csquery 2. 测试的内容 学习了解csquery 3. 代码 添加csquery 的就不用写了 测试的例子是获取我的博客的信息,使用webbrowser 控件 ...

  10. CentOS6.4系统启动失败故障排查

    转:http://www.centoscn.com/CentosBug/osbug/2014/1028/4011.html 操作系统启动失败如下图报错: 故障现象: 从图中可以看到,操作系统启动的过程 ...