Mutex

 一、什么是 Mutex ?

 互斥体又称同步基元。

二、作用:

当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。

三、作用域:

 

Mutex 有两种类型:未命名的局部 mutex 和已命名的系统 mutex。

局部互斥体仅存在于您的进程内。您的进程中任何引用表示 mutex 的 Mutex 对象的线程都可以使用它。每个未命名的 Mutex 对象都表示一个单独的局部 mutex。

已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动 

举例说明:

      //局部Mutex

      Mutex _localSync = new Mutex();

     //系统Mutex

       Mutex _processSync = new Mutex(true, "Name",out owned);

四、应用场景: 

1、使用系统Mutex实现进程间同步与互斥--应用程序启动单实例。


using System;

using System.Collections.Generic;
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

// 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.
    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(0x100001false, name);
            
if (!mutexHandle.IsInvalid)
            {
                num 
= 0xb7;
                
if (Environment.IsW2k3)
                {
                    SafeWaitHandle handle 
= Win32Native.OpenMutex(0x100001false, 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, true0);
                            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,里面有更具体描述。

posted on 2011-03-14 23:30  廖鸿  阅读(7060)  评论(1编辑  收藏  举报

导航