在上一讲介绍了使用lock来实现C#线程同步。实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类。先看看下面的C#源代码:

  1. public static void MyLock() 
  2. lock (typeof(Program)) 
  3. }

上面的代码通过lock语句使MyLock同步,这个方法被编译成IL后,代码如图1所示。

图1

从上图被标注的区域可以看到,一条lock语句被编译成了调用Monitor的Enter和Exit方法。Monitor在 System.Threading命名空间中。lock的功能就相当于直接调用Monitor的Entry方法,所不同的是,lock方法在结束后,会自动解除锁定,当然,在IL中是调用了Monitor的Exit方法,但在C#程序中,看起来是自动解锁的,这类似于C#中的using语句,可以自动释放数据库等的资源。但如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。如下面的代码所示:

  1. Monitor.Entry(lockObj); 
  2. try
  3. // lockObj的同布区 
  4. catch(Exception e) 
  5. // 异常处理代码 
  6. finally
  7. Monitor.Exit(lockObj);  // 解除锁定 
  8. }

Exit方法最后在finally里调用,这样无论在方法在发生异常、返回还是正常执行,都会执行到finally,并调用Exit方法解除锁定。

Monitor类不仅可以完全取代lock语句(如果只使用lock语句本身的功能,最好还是直接用lock语句吧),还可以使用TryEntry方法设置一个锁定超时,单位是毫秒。如下面的代码所示:

  1. if(Monitor.TryEntry(lockObj, 1000)) 
  2. try
  3. finally
  4. Monitor.Exit(lockObj); 
  5. else
  6. // 超时后的处理代码 
  7. }

上面的代码设置了锁定超时时间为1秒,也就是说,在1秒中后,lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁,如下面的代码所示:

  1. class Program 
  2. private static Object objA = new Object(); 
  3. private static Object objB = new Object(); 
  4. public static void LockA() 
  5. if (Monitor.TryEnter(objA, 1000)) 
  6. Thread.Sleep(1000); 
  7. if (Monitor.TryEnter(objB, 2000)) 
  8. Monitor.Exit(objB); 
  9. else
  10. Console.WriteLine("LockB timeout"); 
  11. Monitor.Exit(objA); 
  12. Console.WriteLine("LockA"); 
  13. public static void LockB() 
  14. if (Monitor.TryEnter(objB, 2000)) 
  15. Thread.Sleep(2000); 
  16. if (Monitor.TryEnter(objA, 1000)) 
  17. Monitor.Exit(objA); 
  18. else
  19. Console.WriteLine("LockA timeout"); 
  20. Monitor.Exit(objB); 
  21. Console.WriteLine("LockB"); 
  22. public static void Main() 
  23. Thread threadA = new Thread(LockA); 
  24. Thread threadB = new Thread(LockB); 
  25. threadA.Start(); 
  26. threadB.Start(); 
  27. Thread.Sleep(4000);          
  28. Console.WriteLine("线程结束"); 
  29. }

上面的代码是在上一讲举的死锁的例子,但在这一讲将lock语句改成了TryEntry方法,而且设置了锁定超时间,由于在等待一定时间后,不管被锁定的对象是否被解锁,TryEntry方法都会返回,因此,上面的代码是不会死锁的。运行上面的代码的结果如图2所示。

图2

如果TryEntry方法的超时时间为System.Threading.Timeout.Infinite,TryEntry方法就相当于Entry方法,如果超时时间为0,不管是否解锁,TryEntry方法都会立即返回。

这样就解决了C#线程同步与死锁的问题

C#线程同步与死锁Monitor的更多相关文章

  1. C#:多线程、线程同步与死锁

    推荐阅读: C#线程系列讲座(1):BeginInvoke和EndInvoke方法 C#线程系列讲座(2):Thread类的应用 C#线程系列讲座(3):线程池和文件下载服务器 C#线程系列讲座(4) ...

  2. 线程同步 – lock和Monitor

    在多线程代码中,多个线程可能会访问一些公共的资源(变量.方法逻辑等等),这些公共资源称为临界区(共享区):临界区的资源是不安全,所以需要通过线程同步对多个访问临界区的线程进行控制. 同样,有些时候我们 ...

  3. Java之线程,常用方法,线程同步,死锁

    1, 线程的概念 进程与线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...

  4. java 线程同步、死锁

    转载地址:速学堂 https://www.sxt.cn/Java_jQuery_in_action/eleven-thread-synchronization.html 什么是线程同步  同步问题的提 ...

  5. java ->多线程_线程同步、死锁、等待唤醒机制

    线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. l  我们通过一个案例,演示线 ...

  6. Java线程同步与死锁认识

    讲下自己的认识,算小小的总结吧! synchroized 具有同步线程的功能,它的处理机制类似于给参数里面的对象赋一个标记值,来表明当前状态,当程序里面某个线程执行synchroized里面的代码段时 ...

  7. C# 线程同步之排它锁/Monitor监视器类

    一.Monitor类说明,提供同步访问对象的机制. 1.位于System.Threading命名空间下,mscorlib.dll程序集中. 2.Monitor通过获取和释放排它锁的方式实现多线程的同步 ...

  8. 线程同步、死锁和通信——Java多线程(二)

    一.多线程同步 上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题. 1.同步代码块 class ...

  9. 四十四、Linux 线程——线程同步之死锁以及线程和信号

    44.1 死锁 死锁: 两个线程试图同时占有两个资源,并按不同的次序锁定相应的共享资源 解决方式: 按相同的次序锁定相应的共享资源 使用函数 pthread_mutex_trylock(),它是函数 ...

随机推荐

  1. [leetcode DP]70. Climbing Stairs

    一共有n个台阶,每次跳一个或者两个,有多少种走法,典型的Fibonacii问题 class Solution(object): def climbStairs(self, n): if n<0: ...

  2. [leetcode DP]64. Minimum Path Sum

    一个m*n的表格,每个格子有一个非负数,求从左上到右下最短的路径值 和62,63两个值是同一个思路,建立dp表,记录每个位置到右下角的最短路径的值 class Solution(object): de ...

  3. opencv 加载 修改 保存 图像

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; /* 1 加载图像 cv::imre ...

  4. BZOJ3611 HEOI2014大工程

    先建虚树,然后统计答案. 对于这个两点间最大值和最小值的操作我参考了hzwer的代码. 建虚树时注意判自环 By:大奕哥 #include<bits/stdc++.h> using nam ...

  5. bzoj 2460 拟阵+判线性相关

    /************************************************************** Problem: 2460 User: idy002 Language: ...

  6. Codeforces Beta Round #97 (Div. 1) B. Rectangle and Square 暴力

    B. Rectangle and Square 题目连接: http://codeforces.com/contest/135/problem/B Description Little Petya v ...

  7. Linux中文件/文本的中文乱码解决方法

    Linux显示在Windows编辑过的中文就会显示乱码是由于两个操作系统使用的编码不同所致.Linux下使用的编码是utf8,而Windows使用的是gb18030.因此,解决Linux打开txt/c ...

  8. PHP self与static区别

    this,static和self. self和this还是很好区分的,可是self和static就很糊涂了,两者都能调用静态的方法和属性,看似使用上没有什么太大的分别,但是实际上分别很大,先来看下面这 ...

  9. java编译优化

    #java编译器对`String常量表达式`的优化:  - 1.String+String 可以被编译器识别为常量表达 String a="ab" ; String b=" ...

  10. 极路由通过SSH添加静态路由表之后无法跳转的问题

    1.确定系统已经开启了转发功能: /etc/sysctl.conf下的配置项目为net.ipv4.ip_forward = 1 2.关闭防火墙的REJECT,也就是修改/etc/config/fire ...