基元线程同步构造之 Mutes(互斥体)
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。
互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section)。
因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。任何线程在进入临界区之前,必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。什么时候需要使用互斥体呢?互斥体用于保护共享的易变代码,也就是,全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。
互斥体(mutex)代表一个互斥的锁。它的工作方式和AutoResetEvent(或者计数为1的Semaphore)相似,因为所有这三种构造一次都只释放一个正在等待的线程,实例化一个mutex时,就默认释放了一个正在等待的线程,类似于初始化了一个 new AutoResetEvent(true)。下面展示了Mutex类的样子:
public sealed class Mutex:WaitHandle{
public Mutex();
public void ReleaseMutex();
}
互斥体有一些而外的逻辑在里面,这造成它们比其他构造更复杂。首先,Mutex对象会查询调用线程的Int32ID,记录是那个线程获得了他。一个线程调用ReleaseMutex时,Mutex确保调用线程就是获取Mutex的那个线程。如若不然,Mutex对象的状态就不会改变,而ReleaseMutex会抛出一个System.ApplicationException.除此之外,如果拥有Mutex的一个线程因为任务原因而终止,那么在一个Mutex上等待的一个线程会因为抛出一个System.Threading.AbandonedMutexException异常而被唤醒。通常,这个异常会成为未处理的异常,从而终止整个线程。这是一件好事,因为一个线程在获取了一个Mutex之后,可能在它更新完Mutex所保护的数据之前终止。如果一个线程捕捉了AbandonedMutexException,就可能试图访问损坏的数据,造成无法预料的结果和安全问题。
其次,Mutex对象维护着一个递归计数,它指明拥有该mutex的线程拥有了它多少次。如果一个线程当前拥有一个Mutex,然后该线程再次在Mutex上等待,递归计数将递增,这个线程允许继续运行。线程调用ReleaseMutex时,递归计数递减。只有在递归计数变成0时,另一个线程才能成为该mutex的所有者。
大多数人都不喜欢这个额外的逻辑。这些“功能”是要付出代价的。Mutex对象需要更多的内存来容纳额外的线程ID和递归计数信息。另外,更重要的是,Mutex代码必须维护这些信息,这使锁变得更慢。如果一个应用程序需要(或希望)这些而外的功能,那么应用程序的代码可以自己来实现;代码不一定非要放到Mutext对象中。因此,许多人都会避免使用Mutex对象。
当两个或者更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取互斥体的第二个线程将被挂起,知道第一个线程释放该互斥体。
可以使用WaitHandle.WaitOne方法请求互斥体的所属权。拥有互斥体的线程可以对WaitOne的重复调用中请求相同的互斥体而不会阻止其执行。但线程必须调用ReleaseMutex方法同样多的次数以释放互斥体的所属权。Mutex类强制线程标识,因此互斥体只能由获得它的线程释放。相反,Semaphore类不强制线程标识.
如果线程在拥有互斥体是终止,则称此互斥体被放弃。将此mutex的状态设置为收到信号,下一个等待线程将获得所有权。从.net FrameWork 2.0版开始,在获取被放弃mutex的下一个线程中将引发AbandonedMutexException.在.net Framework 2.0版之前,这样不会引发任何异常.
警告:如果出现被放弃的Mutex,通常表明代码中存在严重错误。如果某个线程在未释放互斥体时便退出,受此互斥体保护的数据结构可能处于不一致的状态。如果此数据结构的完整性能得到验证,下一个请求此互斥体所属权的线程就可以处理此异常并继续。
对于系统范围的mutex,被放弃的mutex可能指示应用程序已突然终止(例如,通过使用windows任务管理器终止)。
Mutex有两种类型:未命名的局部mutex和已命名的系统mutex.本地mutex仅存在于进程当中。您的进程中任何引用表示mutex的Mutex对象的下称都可以使用它。每个未命名的mutex对象都表示一个单独的局部mutex.
已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动。您可以使用接受名称的构造函数创建表示已命名系统mutex的Mutex对象。同时也可以创建操作系统对象,或者它在创捷mutex对象之前就已存在。您可以创建多个Mutex对象来表示同一命名系统Mutex,而且您可以使用OpenExisting方法打开现有的命名系统mutex.
说明:在运行终端服务的服务器上,已命名的系统 mutex 可以具有两级可见性。 如果名称以前缀“Global\”开头,则 mutex 在所有终端服务器会话中均为可见。 如果名称以前缀“Local\”开头,则 mutex 仅在创建它的终端服务器会话中可见。 在这种情况下,服务器上各个其他终端服务器会话中都可以拥有一个名称相同的独立 mutex。 如果创建已命名 mutex 时不指定前缀,则它将采用前缀“Local\”。 在终端服务器会话中,只是名称前缀不同的两个 mutex 是独立的 mutex,这两个 mutex 对于终端服务器会话中的所有进程均为可见。 即:前缀名称“Global\”和“Local\”说明 mutex 名称相对于终端服务器会话(而并非相对于进程)的范围。
说明:应用到此类型或成员的 HostProtectionAttribute 特性具有以下 Resources 属性值:Synchronization | ExternalThreading。HostProtectionAttribute 不影响桌面应用程序(通常通过双击图标、键入命令或在浏览器中输入 URL 来启动这些应用程序)。有关更多信息,请参见 HostProtectionAttribute 类或 SQL Server 编程和宿主保护特性。
示例:此示例演示如何使用局部 Mutex 对象来同步对受保护资源的访问。
// This example shows how a Mutex is used to synchronize access
// to a protected resource. Unlike Monitor, Mutex can be used with
// WaitHandle.WaitAll and WaitAny, and can be passed across
// AppDomain boundaries. using System;
using System.Threading; class Test
{
// Create a new Mutex. The creating thread does not own the
// Mutex. 实例化一个Mutex时,默认就解除了一个等待的线程的阻塞.Mutex调用WaitOne时,就解除了阻塞,类似于实例化了:new AutoResetEvent(true).
private static Mutex mut = new Mutex();
private const int numIterations = ;
private const int numThreads = ; static void Main()
{
// Create the threads that will use the protected resource.
for(int i = ; i < numThreads; i++)
{
Thread myThread = new Thread(new ThreadStart(MyThreadProc));
myThread.Name = String.Format("Thread{0}", i + );
myThread.Start();
} // The main thread exits, but the application continues to
// run until all foreground threads have exited.
} private static void MyThreadProc()
{
for(int i = ; i < numIterations; i++)
{
UseResource();
}
} // This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
mut.WaitOne(); Console.WriteLine("{0} has entered the protected area",
Thread.CurrentThread.Name); // Place code to access non-reentrant resources here. // Simulate some work.
Thread.Sleep(); Console.WriteLine("{0} is leaving the protected area\r\n",
Thread.CurrentThread.Name); // Release the Mutex.
mut.ReleaseMutex();
}
}
这是参考MSDN中的学习心得。。。。。。。。。。http://msdn.microsoft.com/zh-cn/library/System.Threading.Mutex(v=vs.110).aspx
基元线程同步构造之 Mutes(互斥体)的更多相关文章
- 【C#进阶系列】28 基元线程同步构造
多个线程同时访问共享数据时,线程同步能防止数据损坏.之所以要强调同时,是因为线程同步问题实际上就是计时问题. 不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗 ...
- [.net]基元线程同步构造
/* 基元线程同步构造 用户模式构造: 易变构造(Volatile Construct) 互锁构造(Interlocked Construct):自旋锁(Spinlock) 乐观锁(Optimisti ...
- 基元线程同步构造之waithandle中 waitone使用
在使用基元线程同步构造中waithandle中waitone方法的讲解: 调用waithandle的waitone方法阻止当前线程(提前是其状态为Nonsignaled,即红灯),直到当前的 Wait ...
- Clr Via C#读书笔记----基元线程同步构造
线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...
- 基元线程同步构造 AutoResetEvent和ManualResetEvent 线程同步
在.Net多线程编程中,AutoResetEvent和ManualResetEvent这两个类经常用到, 他们的用法很类似,但也有区别.ManualResetEvent和AutoResetEvent都 ...
- CLR via C# I/O基元线程同步构造
1. 分为用户模式构造和内核模式构造 2. 用户模式构造 a.易失构造 在一个简单数据类型的变量上执行原子性读或写操作 VolaileWrite 强制address中的值在调用时写入,除此之外,按照源 ...
- 基元线程同步构造之信号量(Semaphore)
信号量(semaphore)不过是由内核维护的 int32变量而已,(说通俗点就是好比一个线程容器里面允许执行的线程数,0计数就是允许执行的0个线程数,1就是允许执行的1个线程数,2就是允许执行的2个 ...
- 【C#进阶系列】29 混合线程同步构造
上一章讲了基元线程同步构造,而其它的线程同步构造都是基于这些基元线程同步构造的,并且一般都合并了用户模式和内核模式构造,我们称之为混合线程同步构造. 在没有线程竞争时,混合线程提供了基于用户模式构造所 ...
- 【C#】C#线程_基元线程的同步构造
目录结构: contents structure [+] 简介 为什么需要使用线程同步 线程同步的缺点 基元线程同步 什么是基元线程 基元用户模式构造和内核模式构造的比较 用户模式构造 易变构造(Vo ...
随机推荐
- JZ2440 裸机驱动 第8章 NAND Flash控制器
本章目标 了解NAND Flash 芯片的接口 掌握通过NAND Flash控制器访问NAND Flash的方法 8.1 NAND Flash介绍和NAND Flash控制器使用 NAND ...
- ASP.NET网站权限设计实现(一)——使用PowerDesigner进行数据库设计
这里用PowerDesigner做一个初步的设计,后面可能会有修改. 1.启动PowerDesigner新建物理数据模型 2.工具栏 3.新建表模型 4.添加第一张表,可以双击表或右键菜单打开下面窗口 ...
- Django 命令行工具django-admin.py与manage.py
django-admin.py是Django的一个用于管理任务的命令行工具,manage.py是对django-admin.py的简单包装,每个Django Project里面都会包含一个manage ...
- Linux系统管理员非常使用的几款工具推荐
1. ExplainShell.com 命令解释 对于Linux用户来说每天都会写各种命令和脚本,那么你可以使用这个网站工具来查看命令式如何工作的,这样可以避免不必要的错误出现:也是一个很好的学习命令 ...
- [转]C# 使用代理访问网络
本文部分内容来自:https://zhidao.baidu.com/question/563196409.html 也可以参考:http://www.cnblogs.com/stuart/p/5442 ...
- 廖雪峰Java1-2Java程序基础-2变量和数据类型
1.变量 变量是可以持有某个基本类型的数值,或者指向某个对象. 变量必须先定义后使用 定义: 变量类型 变量名 = 初始值; 2.java基本数据类型 整数类型:long int short byte ...
- FiddlerCoreAPI 使用简介
原文:https://blog.csdn.net/zhang116868/article/details/49406599 大名鼎鼎的Fiddler大家都知道,或者用过,Fiddler 开放了他的Fi ...
- PHP下载文件的几种方案
PHP下载远程文件的3种方法以及性能考虑 2014-02-21 0个评论 收藏 我要投稿 今天在做导出Excel的时候,总是要测试导出的Excel文件,频繁的下载和打开,很 ...
- Lunce编程模型
问题的场景: 解决方案:都是来自于科技论文 ============================================================================== ...
- 伯克利推出「看视频学动作」的AI智能体
伯克利曾经提出 DeepMimic框架,让智能体模仿参考动作片段来学习高难度技能.但这些参考片段都是经过动作捕捉合成的高度结构化数据,数据本身的获取需要很高的成本.而近日,他们又更进一步,提出了可以直 ...