Mutex
一、什么是 Mutex ?
互斥体又称同步基元。
二、作用:
当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
三、作用域:
Mutex 有两种类型:未命名的局部 mutex 和已命名的系统 mutex。
局部互斥体仅存在于您的进程内。您的进程中任何引用表示 mutex 的 Mutex 对象的线程都可以使用它。每个未命名的 Mutex 对象都表示一个单独的局部 mutex。
已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动
举例说明:
//局部Mutex
Mutex _localSync = new Mutex();
//系统Mutex
Mutex _processSync = new Mutex(true, "Name",out owned);
四、应用场景:
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Diagnostics;
using Nick.Win32Api;
public class SingleProgramInstance : IDisposable
{
private Mutex _processSync;
private bool _owned = false;
public SingleProgramInstance()
{
_processSync = new Mutex(
true,
Assembly.GetExecutingAssembly().GetName().Name,
out _owned);
}
public SingleProgramInstance(string identifier)
{
_processSync = new Mutex(
true,
Assembly.GetExecutingAssembly().GetName().Name + identifier,
out _owned);
}
~SingleProgramInstance()
{
Release();
}
public bool IsSingleInstance
{
get { return _owned; }
}
public void RaiseOtherProcess()
{
Process proc = Process.GetCurrentProcess();
string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
foreach (Process otherProc in Process.GetProcessesByName(assemblyName))
{
//ignore this process
if (proc.Id != otherProc.Id)
{
IntPtr hWnd = otherProc.MainWindowHandle;
if (Win32Api.IsIconic(hWnd))
{
Win32Api.ShowWindowAsync(hWnd, Win32Api.SW_RESTORE);
}
Win32Api.SetForegroundWindow(hWnd);
return;
}
}
}
private void Release()
{
if (_owned)
{
//If we owne the mutex than release it so that
// other "same" processes can now start.
_processSync.ReleaseMutex();
_owned = false;
}
}
#region Implementation of IDisposable
public void Dispose()
{
//release mutex (if necessary) and notify
// the garbage collector to ignore the destructor
Release();
GC.SuppressFinalize(this);
}
#endregion
}
2、使用局部Mutex实现进程内线程同步.
// This example shows how a Mutex is used to synchronize access
// 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.
private static Mutex mut = new Mutex();
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
{
// Create the threads that will use the protected resource.
for(int i = 0; i < numThreads; i++)
{
Thread myThread = new Thread(new ThreadStart(MyThreadProc));
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.
}
private static void MyThreadProc()
{
for(int i = 0; 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(500);
Console.WriteLine("{0} is leaving the protected area\r\n",
Thread.CurrentThread.Name);
// Release the Mutex.
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 代码如下:
private static int CreateMutexHandle(bool initiallyOwned, string name, Win32Native.SECURITY_ATTRIBUTES securityAttribute, out SafeWaitHandle mutexHandle)
bool flag = false;
bool flag2 = false;
bool flag3 = false;
Label_0006:
flag2 = false;
flag3 = false;
mutexHandle = Win32Native.CreateMutex(securityAttribute, initiallyOwned, name);
int num = Marshal.GetLastWin32Error();
if (!mutexHandle.IsInvalid || (num != 5))
{
return num;
}
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)
{
SafeWaitHandle handle = Win32Native.OpenMutex(0x100001, false, name);
if (!handle.IsInvalid)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
uint num2 = 0;
IntPtr ptr = mutexHandle.DangerousGetHandle();
IntPtr ptr2 = handle.DangerousGetHandle();
IntPtr[] handles = new IntPtr[] { 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);
}
else if ((num2 >= 0x80) && (num2 < 130))
{
Win32Native.ReleaseMutex(mutexHandle);
Win32Native.ReleaseMutex(handle);
}
mutexHandle.Dispose();
}
goto Label_0166;
}
finally
{
handle.Dispose();
}
}
mutexHandle.Dispose();
flag3 = true;
}
}
else
{
num = Marshal.GetLastWin32Error();
}
}
finally
{
if (flag)
{
Thread.EndThreadAffinity();
}
}
Label_0166:
if ((flag2 || flag3) || (num == 2))
{
goto Label_0006;
}
if (num == 0)
{
num = 0xb7;
}
return num;
}
总之,Mutex 在进程、线程之间同步中有重要的作用,其它相关详细的资料请查看MSDN,里面有更具体描述。