这篇文章主要介绍了C#中lock死锁的用法,对于共享资源的访问及C#程序设计的安全性而言,有着非常重要的意义!需要的朋友可以参考下

链接:http://www.jb51.net/article/54309.htm

在c#中有个关键字lock,它的作用是锁定某一代码块,让同一时间只有一个线程访问该代码块,本文就来谈谈lock关键字的原理和其中应注意的几个问题:

lock的使用原型是:

1
2
3
4
lock(X)
{
  //需要锁定的代码....
}

首先要明白为什么上面这段话能够锁定代码,其中的奥妙就是X这个对象,事实上X是任意一种引用类型,它在这儿起的作用就是任何线程执行到lock(X)时候,X需要独享才能运行下面的代码,若假定现在有3个线程A,B,C都执行到了lock(X)而ABC因为此时都占有X,这时ABC就要停下来排个队,一个一个使用X,从而起到在下面的代码块内只有一个线程在运行(因为此时只有一个线程独享X,其余两个在排队),所以这个X必须是所有要执行临界区域代码进程必须共有的一个资源,从而起到抑制线程的作用。

下面再来谈谈lock使用中会遇到和注意的问题,lock最需要注意的一个问题就是线程死锁!

在MSDN上列出了3个典型问题:

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

如果实例可以被公共访问,将出现 lock (this) 问题。

如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。

由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。

最佳做法是定义 private 对象来锁定, 或 private shared 对象变量来保护所有实例所共有的数据。

(1)lock (this) 问题:

假定有两个类:

1
2
class A{}
class B{}

有两个公共对象:

1
2
A a=new A();
B b=new B();

首先在A中若有一函数内的代码需要锁定:

代码1:

1
2
3
4
5
6
7
8
lock(this)//this在这里就是a
{
 //....
 lock(b)
 {
//......
 }
}

然而此时B中某函数也有如下代码需要锁定:

代码2:

1
2
3
4
5
6
7
8
lock(this)//this在这里就是b
{
 //....
 lock(a)
 {
//......
 }
}

设想一下上面两段代码在两个线程下同时执行会有什么后果?

结果就是,代码1执行到lock(this)后a被锁定,代码2执行到lock(this)后b被锁定,然后代码1需求b,代码2需求a,此时两个需求都被相互占有出现僵持状态,程序死锁了。

(2)lock(typeof (MyType))问题:

假定有两个公共变量:

1
int a;float b;

下面看如下代码

代码3:

1
2
3
4
5
6
7
8
lock(typeof(a))//typeof(a)就是System.type.Int类型
{
 //....
 lock(typeof(b))
 {
//......
 }
}

又有如下代码:

代码4:

1
2
3
4
5
6
7
8
lock(typeof(b))//typeof(b)就是System.type.Float类型
{
 //....
 lock(typeof(a))
 {
//......
 }
}

若有两个进程分别同时进入上面两个代码外层的lock,就分别锁定了System.type.Int和System.type.Float,而马上它们又需求System.type.Float和System.type.Int,彼此相互占有,彼此僵持,程序进入死锁状态!

(3)字符串问题 :

在阐述这个问题之前,有一个知识大家必须知道:C#中字符串被公共语言运行库 (CLR)“暂留”。这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。

言下之意就是假定有两个类分别有两个字符串:

1
2
3
4
5
6
7
8
9
10
11
class A
{
 string a="abc";
 string b="def";
}
 
class c
{
 string c="abc";
 string d="def";
}

事实上a和c引用的是同一个字符串"abc",b和d引用的是同一个字符串"def"

现在如果在两个类中有如下代码

在类A中有代码5:

1
2
3
4
5
6
7
8
lock(b)//b是"def"
{
 //....
 lock(a)//a是"abc"
 {
//......
 }
}

在类B中有代码6:

1
2
3
4
5
6
7
8
lock(c)//c是"abc"
{
 //....
 lock(d)//d是"def"
 {
//......
 }
}

那么代码5和代码6同时有两个线程执行结果可想而知:在两个线程执行到外层lock代码时"def"和"abc"被锁定。接着他们在内部lock处同时需求"abc"和"def",而此时两个字符串被两个进程彼此占有,程序又死锁了!所以MSDN说:锁定字符串尤其危险!最好不要使用!

MSDN最后说了:最佳做法是定义 private 对象来锁定, 或 private shared 对象变量来保护所有实例所共有的数据。 
在个人看来,也不是绝对安全,这里就举出一个例子:

假定有一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class A
{
 private Object a=new Object();
 private Object b=new Object();
 public void x()
 {
  lock(a)
  {
    //.....
    lock(b)
    {
     //....
    }
  }
 }
 public void y()
 {
  lock(b)
  {
    //.....
    lock(a)
    {
     //....
    }
  }
 }
}

现在假定有两个线程同时执行函数x()和y();结果private对象a和b分别在外层lock锁定,接着两个线程在内部又立马需求b和a,a,b彼此占有又彼此需求,程序死锁。

所以具体要看情况而定,但是定义 private 对象来锁定至少可以降低风险。

希望本文所述C#中lock的应用对大家的C#程序设计有所帮助。

C#中lock死锁实例教程的更多相关文章

  1. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

  2. [Python][flask][flask-wtf]关于flask-wtf中API使用实例教程

    简介:简单的集成flask,WTForms,包括跨站请求伪造(CSRF),文件上传和验证码. 一.安装(Install) 此文仍然是Windows操作系统下的教程,但是和linux操作系统下的运行环境 ...

  3. c#初学-多线程中lock用法的经典实例

    本文转载自:http://www.cnblogs.com/promise-7/articles/2354077.html 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被 ...

  4. 多线程中lock用法的经典实例

    多线程中lock用法的经典实例 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.它可以把一段代码定义为互斥段(critical section),互斥段在一 ...

  5. Web 开发中应用 HTML5 技术的10个实例教程

    HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...

  6. Android中ViewPager实现滑动条及与Fragment结合的实例教程

    ViewPager类主要被用来实现可滑动的视图功能,这里我们就来共同学习Android中ViewPager实现滑动条及与Fragment结合的实例教程,需要的朋友可以参考下 自主实现滑动指示条先上一个 ...

  7. 一个线程中lock用法的经典实例

    /* 该实例是一个线程中lock用法的经典实例,使得到的balance不会为负数 同时初始化十个线程,启动十个,但由于加锁,能够启动调用WithDraw方法的可能只能是其中几个 作者:http://h ...

  8. 深入浅出SQL Server中的死锁

    简介 死锁的本质是一种僵持状态,是多个主体对于资源的争用而导致的.理解死锁首先需要对死锁所涉及的相关观念有一个理解. 一些基础知识 要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理 ...

  9. 14.5.5.1 An InnoDB Deadlock Example 一个InnoDB 死锁实例

    14.5.5.1 An InnoDB Deadlock Example 一个InnoDB 死锁实例 下面的例子演示了一个错误可以发生当一个lock 请求会导致一个死锁,例子设计2个客户端,A和B: J ...

随机推荐

  1. PowerDesigner设置一对一关系

    (1)修改Cardinalities 为One-one (2)设置Dominant role A->B(假设表A,表B),保存 (3)到Joins页,设置Parent为None,设置Parent ...

  2. redis的常用命令及实例讲解

    使用命令行操作redis 数据类型 字符串String 列表list 使用双向循序链表实现(LinkedList) 散列 Hash 一般应用于将redis作为分布式缓存,存储数据库中的数据对象 集合s ...

  3. set用法

    set的用法一直拖着,今天才算真正会了,小小总结一下(我好菜啊啊啊) #include<bits/stdc++.h> using namespace std; ]; int main(){ ...

  4. 【U3d】Tiled2Unity 使用Tips

    Tiled编辑完地图后借Tiled2Unity导入Unity. 使用T2U时遇到点麻烦,打开T2U界面显示如下,注意上方黄底文字,需要在Tiled中添加命令行才能使用T2U. 在Tiled工具栏点击( ...

  5. IEEE signal processing letters 投稿经验

    转自:http://emuch.net/t.php?tid=6226942 前段时间比较幸运地中了一篇spl,把自己浅薄的经验写出来,直接从自己博客上转过来,分享给大家,望抛砖引玉吧~~~ 从投稿到录 ...

  6. [机器学习笔记]奇异值分解SVD简介及其在推荐系统中的简单应用

    本文先从几何意义上对奇异值分解SVD进行简单介绍,然后分析了特征值分解与奇异值分解的区别与联系,最后用python实现将SVD应用于推荐系统. 1.SVD详解 SVD(singular value d ...

  7. qt5下载与安装,VS2017的环境配置

    下载地址  http://download.qt.io/archive/qt/ 安装 选择安装路径 ,只有没有中文即可 二.Qt与VS2017相关联 1.打开VS2017,选择工具 - 拓展和更新 2 ...

  8. 【Vue】定义组件 data 必须是一个函数返回的对象

    Vue 实例的数据对象.Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化.对象必须是纯粹的对象 (含有零个或多个的 key/value ...

  9. Python基础3(2017-07-20)

    1.文件操作 现有文件如下: We were both young when I first saw you 当我第一次看见你的时候,我们都还年轻 I close my eyes and the fl ...

  10. JVM内存分配及GC流程

    -verbose 这是查询GC问题最常用的命令之一,具体参数如: -verbose:class 输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断. -verbose:gc 输 ...