C#多线程学习(六) 互斥对象
来源:互联网 发布:淘宝的红包口令在哪里 编辑:程序博客网 时间:2024/05/18 07:03
本文参考MSDN总结
当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
可以使用 WaitHandle.WaitOne 方法请求互斥体的所属权。拥有互斥体的线程可以在对 WaitOne 的重复调用中请求相同的互斥体而不会阻止其执行。但线程必须调用 ReleaseMutex 方法同样多的次数以释放互斥体的所属权。Mutex 类强制线程标识,因此互斥体只能由获得它的线程释放。
如果线程在拥有互斥体时终止,则称此互斥体被放弃。此互斥体被设置为终止状态,下一个等待的线程获得所属权。如果没有线程拥有互斥体,则互斥体状态为终止。从 .NET Framework 2.0 版开始,需要该互斥体的下一个线程将引发 AbandonedMutexException。在 .NET Framework 2.0 版之前,这样不会引发任何异常。
出现遗弃的 Mutex 表明存在严重的编码错误。如果某个线程在未释放互斥体时便退出,受此互斥体保护的数据结构可能处于不一致的状态。如果此数据结构的完整性能得到验证,下一个请求此互斥体所属权的线程就可以处理此异常并继续。
互斥体有两种类型:局部互斥体和已命名的系统互斥体。如果使用接受名称的构造函数创建 Mutex 对象,则该对象与具有该名称的操作系统对象关联。已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动。您可以创建多个 Mutex 对象来表示同一个已命名的系统互斥体,也可以使用 OpenExisting 方法打开现有的已命名系统互斥体。
局部互斥体仅存在于您的进程内。您的进程中任何引用局部 Mutex 对象的线程都可以使用它。每个 Mutex 对象都是一个单独的局部互斥体。
我们可以把Mutex看作一个出租车,乘客看作线程。乘客首先等车,然后上车,最后下车。当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车。而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都只有等待。
Mutex例子(参考MSDN代码修改)
using System;
using System.Threading;
using System.Collections;
namespace MutexExample
{
public class MutexTest
{
// Create a new Mutex. The creating thread does not own the
// Mutex.
private Mutex mutex = new Mutex();
private int threadNums = 3;
private void ThreadProc()
{
this.UseResource();
}
private void UseResource()
{
// Wait until it is safe to enter.
mutex.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(500);
Console.WriteLine("{0} is leaving the protected area/r/n",
Thread.CurrentThread.Name);
// Release the Mutex.
mutex.ReleaseMutex();
}
public static void Main(string[] args)
{
Console.WriteLine("Thread Operation Start./n");
MutexTest mutexTest = new MutexTest();
for (int i = 0; i < mutexTest.threadNums; i++)
{
Thread myThread = new Thread(new ThreadStart(mutexTest.ThreadProc));
myThread.Name = String.Format("Thread{0}", i + 1);
myThread.Start();
}
// The main thread exits, but the application continues to
// run until all foreground threads have exited.
Console.ReadLine();
}
}
}
运行结果如下:
一个更加复杂更具代表性的例子:
using System;
using System.Threading;
using System.Collections;
namespace ThreadExample
{
public class MutexSample
{
static Mutex gM1;
static Mutex gM2;
const int ITERS = 100;
static AutoResetEvent Event1 = new AutoResetEvent(false);
static AutoResetEvent Event2 = new AutoResetEvent(false);
static AutoResetEvent Event3 = new AutoResetEvent(false);
static AutoResetEvent Event4 = new AutoResetEvent(false);
public static void Main(String[] args)
{
Console.WriteLine(" Mutex Sample /n");
//创建一个Mutex对象,并且命名为MyMutex
gM1 = new Mutex(true, "MyMutex");
//创建一个未命名的Mutex 对象.
gM2 = new Mutex(true);
Console.WriteLine(" - Main Owns gM1 and gM2/n");
AutoResetEvent[] evs = new AutoResetEvent[4];
evs[0] = Event1; //为后面的线程t1,t2,t3,t4定义AutoResetEvent对象
evs[1] = Event2;
evs[2] = Event3;
evs[3] = Event4;
MutexSample tm = new MutexSample();
Thread t1 = new Thread(new ThreadStart(tm.t1Start));
Thread t2 = new Thread(new ThreadStart(tm.t2Start));
Thread t3 = new Thread(new ThreadStart(tm.t3Start));
Thread t4 = new Thread(new ThreadStart(tm.t4Start));
t1.Start();// 使用Mutex.WaitAll()方法等待一个Mutex数组中的对象全部被释放
t2.Start();// 使用Mutex.WaitOne()方法等待gM1的释放
t3.Start();// 使用Mutex.WaitAny()方法等待一个Mutex数组中任意一个对象被释放
t4.Start();// 使用Mutex.WaitOne()方法等待gM2的释放
Thread.Sleep(2000);
Console.WriteLine("/n - Main releases gM1/n");
gM1.ReleaseMutex(); //线程t2,t3结束条件满足
Thread.Sleep(1000);
Console.WriteLine(" - Main releases gM2/n");
gM2.ReleaseMutex(); //线程t1,t4结束条件满足
//等待所有四个线程结束
WaitHandle.WaitAll(evs);
Console.WriteLine("/n Mutex Sample");
Console.ReadLine();
}
public void t1Start()
{
Console.WriteLine("t1Start started, Mutex.WaitAll(Mutex[])");
Mutex[] gMs = new Mutex[2];
gMs[0] = gM1;//创建一个Mutex数组作为Mutex.WaitAll()方法的参数
gMs[1] = gM2;
Mutex.WaitAll(gMs);//等待gM1和gM2都被释放
Thread.Sleep(2000);
Console.WriteLine("t1Start finished, Mutex.WaitAll(Mutex[]) satisfied");
gM1.ReleaseMutex();
gM2.ReleaseMutex();
Event1.Set(); //线程结束,将Event1设置为有信号状态
}
public void t2Start()
{
Console.WriteLine("t2Start started, gM1.WaitOne( )");
gM1.WaitOne(); //等待gM1的释放
Console.WriteLine("t2Start finished, gM1.WaitOne( ) satisfied");
gM1.ReleaseMutex();
Event2.Set(); //线程结束,将Event2设置为有信号状态
}
public void t3Start()
{
Console.WriteLine("t3Start started, Mutex.WaitAny(Mutex[])");
Mutex[] gMs = new Mutex[2];
gMs[0] = gM1; //创建一个Mutex数组作为Mutex.WaitAny()方法的参数
gMs[1] = gM2;
Mutex.WaitAny(gMs); //等待数组中任意一个Mutex对象被释放
gM1.ReleaseMutex();
Console.WriteLine("t3Start finished, Mutex.WaitAny(Mutex[])");
Event3.Set(); //线程结束,将Event3设置为有信号状态
}
public void t4Start()
{
Console.WriteLine("t4Start started, gM2.WaitOne( )");
gM2.WaitOne(); //等待gM2被释放
Console.WriteLine("t4Start finished, gM2.WaitOne( )");
gM2.ReleaseMutex();
Event4.Set(); //线程结束,将Event4设置为有信号状态
}
}
}
运行结果:
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- C#多线程学习(六) 互斥对象
- php_23种设计模式的趣味解释
- jasperreport + Struts2
- SHUTDOWN常用参数
- win7 IIS 和 ASP.NET的配置
- PHP implode() 函数
- C#多线程学习(六) 互斥对象
- 创建虚拟桌面
- 《盗梦空间》观后感
- ASP.net弹出对话框的几种简单的方式
- DOS指令(管理工具命令)
- 内存对齐。
- 转【定制ROM教程】打造自己喜欢的ROM定制包(不止是修改)
- PHP ucwords() 函数
- Maven安装使用