互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码“临界区”。因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。

  任何线程在进入临界区之前,必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。什么时候需要使用互斥体呢?互斥体用于保护共享的易变代码,也就是,全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。

1、Mutex

  Mutex是一个同步基元,它与前面提到的锁最大的区别在于它支持进程间同步。

  Mutex允许同一个线程多次重复访问共享区,但是对于别的线程那就必须等待,它甚至支持不同进程中的线程同步,这点更能体现他的优势,但是劣势也是显而易见的,那就是巨大的性能损耗和容易产生死锁的困扰,所以除非需要在特殊场合,否则 我们尽量少用为妙,这里并非是将Mutex的缺点说的很严重,而是建议大家在适当的场合使用更为适合的同步方式,Mutex 就好比一个重量型的工具,利用它则必须付出性能的代价。

  1、Mutex线程同步

  Mutex实现线程同步主要依靠以下两个方法实现:

  • WaitOne 阻止当前线程,直到当前 WaitHandle 收到信号。
  • ReleaseMutex 释放 Mutex 一次。
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. for (int i = 0; i < 10; i++)
  6. {
  7. ThreadPool.QueueUserWorkItem(Run);
  8. }
  9.  
  10. Console.Read();
  11. }
  12.  
  13. static int count = 0;
  14.  
  15. static Mutex mutex = new Mutex();
  16.  
  17. static void Run(object obj)
  18. {
  19. //阻止当前线程
  20. mutex.WaitOne();
  21.  
  22. Console.WriteLine("当前数字:{0}", ++count);
  23.  
  24. //释放 Mutex
  25. mutex.ReleaseMutex();
  26. }
  27. }

  输出:

  

  Mutex和Monitor的区别:

  1. Monitor不是waitHandle的子类,它具有等待和就绪队列的实际应用;
  2. Monitor无法跨进程中实现线程同步,但是Mutex可以;
  3. 相对而言两者有明显的性能差距,mutex相对性能较弱但是功能更为强大,monitor则性能比较好;
  4. 两者都是用锁的概念来实现同步不同的是monitor一般在方法(函数)调用方加锁;mutex一般在方法(函数)内部加锁,即锁定被调用端;

  2、进程间同步

  当给Mutex取名的时候能够实现进程同步,不取名实现线程同步。

  Mutex有两种类型:未命名的局部mutex和已命名的系统mutex。

  • 本地mutex仅存在与进程当中,进程内可见;
  • 已命名的系统mutex在整个操作系统中可见,可用于同步进程活动;
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //使用线程输出等待状态
  6. Thread t1 = new Thread(ShowMyWord);
  7. t1.Start();
  8.  
  9. Run(t1);
  10.  
  11. Console.Read();
  12. }
  13.  
  14. static int count = 0;
  15.  
  16. static Mutex mutex = new Mutex(false, "xxoo");
  17. static void Run(Thread t1)
  18. {
  19.  
  20. //这个WaitOne方法要么返回true,要么一直不返回(不会返回false),所以没办法用if来判断
  21. //于是,用个线程输出等待状态
  22. mutex.WaitOne();
  23.  
  24. Console.WriteLine("终于轮到老子了! " + DateTime.Now.TimeOfDay.ToString());
  25. //停止线程t1,不要再输出等待状态
  26. t1.Abort();
  27. //模拟干活十秒
  28. Thread.Sleep(10000);
  29. Console.WriteLine("干完! " + DateTime.Now.TimeOfDay.ToString());
  30.  
  31. //释放 Mutex
  32. mutex.ReleaseMutex();
  33. }
  34.  
  35. static void ShowMyWord(object obj)
  36. {
  37. for (int i = 0; i < 10; i++)
  38. {
  39. Thread.Sleep(2000);
  40. Console.WriteLine("我的心在等待,一直在等待! " + DateTime.Now.TimeOfDay.ToString());
  41. }
  42. }
  43. }

  以上代码,将生成的.exe文件复制两份:

  

  快速运行两个输出如下:

  

二、Interlocked

  实际引用中,可能我们对共享变量的使用并不十分复杂,可能只是一些简单的操作如:自增、自减、求和、赋值、比较等。

  MSDN中的解析Interlocked为多个线程共享的变量提供原子操作。

  常用操作如下:

方法 说明
Add 相加
CompareExchange 比较
Increment 递增
Decrement 递减
Exchange 赋值

  示例:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. for (int i = 0; i < 20; i++)
  6. {
  7. Thread t = new Thread(Run);
  8.  
  9. t.Start();
  10. }
  11.  
  12. Console.Read();
  13. }
  14.  
  15. static int Incre = 0;
  16. static int Add = 0;
  17. static int Exchange = 0;
  18. static int Decre = 21;
  19. static int CompareExchange = 0;
  20.  
  21. static Mutex mutex = new Mutex();
  22.  
  23. static void Run()
  24. {
  25. //自增操作
  26. //Console.WriteLine("当前数字:{0}", Interlocked.Increment(ref Incre));
  27. //递减操作
  28. //Console.WriteLine("当前数字:{0}", Interlocked.Decrement(ref Decre));
  29. //相加
  30. //Console.WriteLine("当前数字:{0}", Interlocked.Add(ref Add,10));
  31. //赋值
  32. //Console.WriteLine("当前数字:{0}", Interlocked.Exchange(ref Exchange, 5));
  33. //比较,如果第三个参数等于CompareExchange,则将第二个参数的值,赋给第一个参数
  34. Console.WriteLine("当前数字:{0}", Interlocked.CompareExchange(ref CompareExchange, 15,0));
  35.  
  36. }
  37. }

互斥体与互锁 <第五篇>的更多相关文章

  1. 转载 互斥体与互锁 <第五篇>

    互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)).互斥体禁止多个线程同时进入受保护的代码“临界区”.因此,在任意时刻,只有一个线程被允许进入这 ...

  2. 【APUE】信号量、互斥体和自旋锁

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...

  3. 【uTenux实验】互斥体

    互斥体,维基百科中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...

  4. mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁

    第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...

  5. boost 互斥体和锁

    1.共享资源是一个自动锁住的房间,互斥体是钥匙,进入房间必须取钥匙,离开房间应该还钥匙.这就对应着互斥体的lock(取钥匙)和unlock(还钥匙). 2.考虑下面的场景:还钥匙的时候出现异常,会发生 ...

  6. 多线程(三)多线程同步_基本介绍及mutex互斥体

    同步进制的引入为了解决以下三个主要问题:1.控制多个线程之间对共享资源访问,保证共享资源的完整性例如:线程A对共享资源进行写入,线程B读取共享资源2.确保多个线程之间的动作以指定的次序发生例如:线程B ...

  7. 第五篇 Replication:事务复制-How it works

    本篇文章是SQL Server Replication系列的第五篇,详细内容请参考原文. 这一系列包含SQL Server事务复制和合并复制的详细内容,从理解基本术语和设置复制的方法,到描述它是如何工 ...

  8. linux 内核的rt_mutex (realtime互斥体)

    linux 内核有实时互斥体(锁),名为rt_mutex即realtime mutex.说到realtime一定离不开priority(优先级).所谓实时,就是根据优先级的不同对任务作出不同速度的响应 ...

  9. 基元线程同步构造之 Mutes(互斥体)

    互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)). 互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section). 因 ...

随机推荐

  1. find详解

    一.简介 在目录结构中搜索文件,并执行指定的操作. 二.语法 find path -option [ -print ] [ -exec -ok command ] {} \;path: find命令所 ...

  2. Openstack no valid hot

    错误: 创建实例 "ce" 失败: 请稍后再试 [错误: No valid host was found. ].

  3. SQLServer 循环1百万插入测试数据

    1,首先创建student表 create table student ( sno int primary key , sname VARCHAR(200) ) 2,--向数据库中插入100万条随机姓 ...

  4. WPF ICommand 用法

    基础类,继承与ICommand接口 using System; using System.Collections.Generic; using System.Linq; using System.Te ...

  5. HDU 1813 Escape from Tetris (IDA*)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1813 题意:给你一个n*n的迷宫,其中0代表有一个人在这个位置,1代表墙,现在要求一个路线,使所有的人通 ...

  6. 浅谈Android系统开发中LOG的使用

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用 ...

  7. ios 自己定义导航栏和切割线

    自己定义导航栏: // CustomNaviBarView.h #import <UIKit/UIKit.h> @interface CustomNaviBarView : UIView ...

  8. Servlet实现Session

    (1)首先看一下项目的结构 是在tomcat--webaps下的myWebSites项目 在myWebSites下有仅仅有WEB-INF目录 在WEB-INF目录中有  一下目录(在classes目录 ...

  9. vue-resource插件使用

    本文的主要内容如下: 介绍vue-resource的特点 介绍vue-resource的基本使用方法 基于this.$http的增删查改示例 基于this.$resource的增删查改示例 基于int ...

  10. JSTL学习笔记(核心标签)

    一.JSTL标签分类: 核心标签 格式化标签 SQL标签 XML标签 JSTL函数 二.核心标签       引用方式:<%@ taglib prefix="c" uri=& ...