互斥体又称同步基元。
二、作用:
当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。
Mutex是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
三、作用域:
Mutex 有两种类型:未命名的局部 mutex 和已命名的系统 mutex。
局部互斥体仅存在于您的进程内。您的进程中任何引用表示 mutex 的 Mutex 对象的线程都可以使用它。每个未命名的Mutex 对象都表示一个单独的局部 mutex。
已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动
举例说明:
//局部Mutex
Mutex _localSync = new Mutex();
//系统Mutex
Mutex _processSync = new Mutex(true,"Name",out owned);
四、应用场景:
1、使用系统Mutex实现进程间同步与互斥--应用程序启动单实例。usingSystem;
usingSystem.Collections.Generic;usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading;
usingSystem.Reflection;
usingSystem.Diagnostics;
usingNick.Win32Api;
publicclassSingleProgramInstance:IDisposable
{
privateMutex_processSync;
privatebool_owned=false;
publicSingleProgramInstance()
{
_processSync=newMutex(
true,
Assembly.GetExecutingAssembly().GetName().Name,
out_owned);
}
publicSingleProgramInstance(stringidentifier)
{
_processSync=newMutex(
true,
Assembly.GetExecutingAssembly().GetName().Name+identifier,
out_owned);
}
~SingleProgramInstance()
{
Release();
}
publicboolIsSingleInstance
{
get{return_owned;}
}
publicvoidRaiseOtherProcess()
{
Processproc=Process.GetCurrentProcess();
stringassemblyName=Assembly.GetExecutingAssembly().GetName().Name;
foreach(ProcessotherProcinProcess.GetProcessesByName(assemblyName))
{
//ignorethisprocess
if(proc.Id!=otherProc.Id)
{
IntPtrhWnd=otherProc.MainWindowHandle;
if(Win32Api.IsIconic(hWnd))
{
Win32Api.ShowWindowAsync(hWnd,Win32Api.SW_RESTORE);
}
Win32Api.SetForegroundWindow(hWnd);
return;
}
}
}
privatevoidRelease()
{
if(_owned)
{
//Ifweownethemutexthanreleaseitsothat
//other"same"processescannowstart.
_processSync.ReleaseMutex();
_owned=false;
}
}
#regionImplementationofIDisposable
publicvoidDispose()
{
//releasemutex(ifnecessary)andnotify
//thegarbagecollectortoignorethedestructor
Release();
GC.SuppressFinalize(this);
}
#endregion
}
2、使用局部Mutex实现进程内线程同步.
//ThisexampleshowshowaMutexisusedtosynchronizeaccess
//toaprotectedresource.UnlikeMonitor,Mutexcanbeusedwith//WaitHandle.WaitAllandWaitAny,andcanbepassedacross
//AppDomainboundaries.
usingSystem;
usingSystem.Threading;
classTest
{
//CreateanewMutex.Thecreatingthreaddoesnotownthe
//Mutex.
privatestaticMutexmut=newMutex();
privateconstintnumIterations=1;
privateconstintnumThreads=3;
staticvoidMain()
{
//Createthethreadsthatwillusetheprotectedresource.
for(inti=0;i<numThreads;i++)
{
ThreadmyThread=newThread(newThreadStart(MyThreadProc));
myThread.Name=String.Format("Thread{0}",i+1);
myThread.Start();
}
//Themainthreadexits,buttheapplicationcontinuesto
//rununtilallforegroundthreadshaveexited.
}
privatestaticvoidMyThreadProc()
{
for(inti=0;i<numIterations;i++)
{
UseResource();
}
}
//Thismethodrepresentsaresourcethatmustbesynchronized
//sothatonlyonethreadatatimecanenter.
privatestaticvoidUseResource()
{
//Waituntilitissafetoenter.
mut.WaitOne();
Console.WriteLine("{0}hasenteredtheprotectedarea",
Thread.CurrentThread.Name);
//Placecodetoaccessnon-reentrantresourceshere.
//Simulatesomework.
Thread.Sleep(500);
Console.WriteLine("{0}isleavingtheprotectedarear",
Thread.CurrentThread.Name);
//ReleasetheMutex.
mut.ReleaseMutex();
}
}
五、实现
C# Mutex 是实现Windows API 的Mutex其原型如下
调用CreateMutex可以创建或打开一个Mutex对象
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
其中参数lpMutexAttributes用来设定Mutex对象的安全描述符和是否允许子进程继承句柄。bInitialOwner表明是否将Mutex的持有者设置为调用线程。lpName参数设置Mutex的名字,该名字区分大小写并不能包含"",最大长度为MAX_PATH,可设置为NULL表明该Mutex为匿名对象。
如果调用成功,则返回Mutex的句柄,否则返回NULL,如果lpName不为NULL且调用前同名的Mutex已被创建,则返回同名Mutex的句柄,此时调用GetLastError将返回ERROR_ALREADY_EXISTS,参数bInitialOwner将被忽略。
还可以调用OpenMutex打开创建的非匿名Mutex,原型如下
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
dotnetFramwork 代码如下:
privatestaticintCreateMutexHandle(boolinitiallyOwned,stringname,Win32Native.SECURITY_ATTRIBUTESsecurityAttribute,outSafeWaitHandlemutexHandle)
{boolflag=false;
boolflag2=false;
boolflag3=false;
Label_0006:
flag2=false;
flag3=false;
mutexHandle=Win32Native.CreateMutex(securityAttribute,initiallyOwned,name);
intnum=Marshal.GetLastWin32Error();
if(!mutexHandle.IsInvalid||(num!=5))
{
returnnum;
}
RuntimeHelpers.PrepareConstrainedRegions();
try
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
finally
{
Thread.BeginThreadAffinity();
flag=true;
}
mutexHandle=Win32Native.OpenMutex(0x100001,false,name);
if(!mutexHandle.IsInvalid)
{
num=0xb7;
if(Environment.IsW2k3)
{
SafeWaitHandlehandle=Win32Native.OpenMutex(0x100001,false,name);
if(!handle.IsInvalid)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
uintnum2=0;
IntPtrptr=mutexHandle.DangerousGetHandle();
IntPtrptr2=handle.DangerousGetHandle();
IntPtr[]handles=newIntPtr[]{ptr,ptr2};
num2=Win32Native.WaitForMultipleObjects(2,handles,true,0);
GC.KeepAlive(handles);
if(num2==uint.MaxValue)
{
if(Marshal.GetLastWin32Error()!=0x57)
{
mutexHandle.Dispose();
flag3=true;
}
}
else
{
flag2=true;
if((num2>=0)&&(num2<2))
{
Win32Native.ReleaseMutex(mutexHandle);
Win32Native.ReleaseMutex(handle);
}
elseif((num2>=0x80)&&(num2<130))
{
Win32Native.ReleaseMutex(mutexHandle);
Win32Native.ReleaseMutex(handle);
}
mutexHandle.Dispose();
}
gotoLabel_0166;
}
finally
{
handle.Dispose();
}
}
mutexHandle.Dispose();
flag3=true;
}
}
else
{
num=Marshal.GetLastWin32Error();
}
}
finally
{
if(flag)
{
Thread.EndThreadAffinity();
}
}
Label_0166:
if((flag2||flag3)||(num==2))
{
gotoLabel_0006;
}
if(num==0)
{
num=0xb7;
}
returnnum;
}
总之,Mutex 在进程、线程之间同步中有重要的作用,其它相关详细的资料请查看MSDN,里面有更具体描述。