互斥体与互锁 <第五篇>
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码“临界区”。因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。
任何线程在进入临界区之前,必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。什么时候需要使用互斥体呢?互斥体用于保护共享的易变代码,也就是,全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。
1、Mutex
Mutex是一个同步基元,它与前面提到的锁最大的区别在于它支持进程间同步。
Mutex允许同一个线程多次重复访问共享区,但是对于别的线程那就必须等待,它甚至支持不同进程中的线程同步,这点更能体现他的优势,但是劣势也是显而易见的,那就是巨大的性能损耗和容易产生死锁的困扰,所以除非需要在特殊场合,否则 我们尽量少用为妙,这里并非是将Mutex的缺点说的很严重,而是建议大家在适当的场合使用更为适合的同步方式,Mutex 就好比一个重量型的工具,利用它则必须付出性能的代价。
1、Mutex线程同步
Mutex实现线程同步主要依靠以下两个方法实现:
- WaitOne 阻止当前线程,直到当前 WaitHandle 收到信号。
- ReleaseMutex 释放 Mutex 一次。
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(Run);
} Console.Read();
} static int count = 0; static Mutex mutex = new Mutex(); static void Run(object obj)
{
//阻止当前线程
mutex.WaitOne(); Console.WriteLine("当前数字:{0}", ++count); //释放 Mutex
mutex.ReleaseMutex();
}
}
输出:
Mutex和Monitor的区别:
- Monitor不是waitHandle的子类,它具有等待和就绪队列的实际应用;
- Monitor无法跨进程中实现线程同步,但是Mutex可以;
- 相对而言两者有明显的性能差距,mutex相对性能较弱但是功能更为强大,monitor则性能比较好;
- 两者都是用锁的概念来实现同步不同的是monitor一般在方法(函数)调用方加锁;mutex一般在方法(函数)内部加锁,即锁定被调用端;
2、进程间同步
当给Mutex取名的时候能够实现进程同步,不取名实现线程同步。
Mutex有两种类型:未命名的局部mutex和已命名的系统mutex。
- 本地mutex仅存在与进程当中,进程内可见;
- 已命名的系统mutex在整个操作系统中可见,可用于同步进程活动;
class Program
{
static void Main(string[] args)
{
//使用线程输出等待状态
Thread t1 = new Thread(ShowMyWord);
t1.Start(); Run(t1); Console.Read();
} static int count = 0; static Mutex mutex = new Mutex(false, "xxoo"); static void Run(Thread t1)
{ //这个WaitOne方法要么返回true,要么一直不返回(不会返回false),所以没办法用if来判断
//于是,用个线程输出等待状态
mutex.WaitOne(); Console.WriteLine("终于轮到老子了! " + DateTime.Now.TimeOfDay.ToString());
//停止线程t1,不要再输出等待状态
t1.Abort();
//模拟干活十秒
Thread.Sleep(10000);
Console.WriteLine("干完! " + DateTime.Now.TimeOfDay.ToString()); //释放 Mutex
mutex.ReleaseMutex();
} static void ShowMyWord(object obj)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(2000);
Console.WriteLine("我的心在等待,一直在等待! " + DateTime.Now.TimeOfDay.ToString());
}
}
}
以上代码,将生成的.exe文件复制两份:
快速运行两个输出如下:
二、Interlocked
实际引用中,可能我们对共享变量的使用并不十分复杂,可能只是一些简单的操作如:自增、自减、求和、赋值、比较等。
MSDN中的解析Interlocked为多个线程共享的变量提供原子操作。
常用操作如下:
方法 | 说明 |
Add | 相加 |
CompareExchange | 比较 |
Increment | 递增 |
Decrement | 递减 |
Exchange | 赋值 |
示例:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
{
Thread t = new Thread(Run); t.Start();
} Console.Read();
} static int Incre = 0;
static int Add = 0;
static int Exchange = 0;
static int Decre = 21;
static int CompareExchange = 0; static Mutex mutex = new Mutex(); static void Run()
{
//自增操作
//Console.WriteLine("当前数字:{0}", Interlocked.Increment(ref Incre));
//递减操作
//Console.WriteLine("当前数字:{0}", Interlocked.Decrement(ref Decre));
//相加
//Console.WriteLine("当前数字:{0}", Interlocked.Add(ref Add,10));
//赋值
//Console.WriteLine("当前数字:{0}", Interlocked.Exchange(ref Exchange, 5));
//比较,如果第三个参数等于CompareExchange,则将第二个参数的值,赋给第一个参数
Console.WriteLine("当前数字:{0}", Interlocked.CompareExchange(ref CompareExchange, 15,0)); }
}
互斥体与互锁 <第五篇>的更多相关文章
- 转载 互斥体与互锁 <第五篇>
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)).互斥体禁止多个线程同时进入受保护的代码“临界区”.因此,在任意时刻,只有一个线程被允许进入这 ...
- 【APUE】信号量、互斥体和自旋锁
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...
- 【uTenux实验】互斥体
互斥体,维基百科中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...
- mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁
第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...
- boost 互斥体和锁
1.共享资源是一个自动锁住的房间,互斥体是钥匙,进入房间必须取钥匙,离开房间应该还钥匙.这就对应着互斥体的lock(取钥匙)和unlock(还钥匙). 2.考虑下面的场景:还钥匙的时候出现异常,会发生 ...
- 多线程(三)多线程同步_基本介绍及mutex互斥体
同步进制的引入为了解决以下三个主要问题:1.控制多个线程之间对共享资源访问,保证共享资源的完整性例如:线程A对共享资源进行写入,线程B读取共享资源2.确保多个线程之间的动作以指定的次序发生例如:线程B ...
- 第五篇 Replication:事务复制-How it works
本篇文章是SQL Server Replication系列的第五篇,详细内容请参考原文. 这一系列包含SQL Server事务复制和合并复制的详细内容,从理解基本术语和设置复制的方法,到描述它是如何工 ...
- linux 内核的rt_mutex (realtime互斥体)
linux 内核有实时互斥体(锁),名为rt_mutex即realtime mutex.说到realtime一定离不开priority(优先级).所谓实时,就是根据优先级的不同对任务作出不同速度的响应 ...
- 基元线程同步构造之 Mutes(互斥体)
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)). 互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section). 因 ...
随机推荐
- DDP和DDU什么区别
DU/DDP 就是A发货给国外B,B只要呆在家里看电视,货会自动送上门,当中的所有运输清关等事情都是由A来负责(A可以委托货代来负责),区别就是DDU是不包括税金的,也就是货值的百分之多少,税金会在B ...
- java.lang.OutOfMemoryError: unable to create new native thread(转)
解决 - java.lang.OutOfMemoryError: unable to create new native thread 工作中碰到过这个问题好几次了,觉得有必要总结一下,所以有了这篇文 ...
- logstash 字段类型转换后 需要刷新
filter { grok { match => [ "message" , "\s*%{IPORHOST:clientip}\s+\-\s+\-\s+\[%{HT ...
- 优化C#程序的48种方法
一.用属性代替可访问的字段 1..NET数据绑定只支持数据绑定,使用属性可以获得数据绑定的好处: 2.在属性的get和set访问器重可使用lock添加多线程的支持. 二.readonly(运行时常量) ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- HTTP缓存 1.0 vs 1.1
在“使用ETag跟踪用户”中有一点被忽略了,因为要用这张小图统计统计uv, 所以要求浏览器必须每次都要发送这个图片的请求.这需要服务器对图片的缓存策略做设置. http/1.0 和 http/1.1 ...
- C#开发客户端、JAVA和tomcat开发服务端
hessian入门,Hello和文件上传范例,C#客户端+Java Tomcat后台 2.Hello范例1)后台--定义Java接口:package org.migle.hessian; public ...
- 最长公共子串LCS(Longest Common Substring)
一.问题描述 寻求两个字符串中的最大公共字串,其中子串是指字符串中连续的字符组成的,而不是像子序列,按照字符的前后顺序组成.如str1="sgabacbadfgbacst",str ...
- 01-Java学习笔记
本系列笔记由常彦博整理,请知悉 目 录 一. Java技术基础.................................................................... ...
- POJ 1300 欧拉通路&欧拉回路
系统的学习一遍图论!从这篇博客开始! 先介绍一些概念. 无向图: G为连通的无向图,称经过G的每条边一次并且仅一次的路径为欧拉通路. 如果欧拉通路是回路(起点和终点相同),则称此回路为欧拉回路. 具有 ...