Mutex 클래스
Mutex 클래스는 Monitor클래스와 같이 특정 코드 블럭(Critiacal Section)을 배타적으로 Locking하는 기능을 가지고 있다. 단, Monitor클래스는 하나의 프로세스 내에서만 사용할 수 있는 반면, Mutex 클래스는 해당 머신의 프로세스간에서도 배타적 Locking을 하는데 사용된다. Mutex 락킹은 Monitor 락킹보다 약 50배 정도 느리기 때문에 한 프로세스내에서만 배타적 Lock이 필요한 경우는 C#의 lock이나 Monitor 클래스를 사용한다. 아래 예제는 MyClass가 외부 프로세스에서도 사용할 수 있다는 가정하에 배타적 Lock으로 뮤텍스를 사용하는 예이다. (실제로는 한 프로세스 내에서 사용할 경우, Monitor를 사용하는 것이 빠른 방식이다)
예제
using System;
using System.Threading;
using System.Collections.Generic;
namespace MultiThrdApp
{
class Program
{
static void Main(string[] args)
{
// 2개의 쓰레드 실행
Thread t1 = new Thread(() => MyClass.AddList(10));
Thread t2 = new Thread(() => MyClass.AddList(20));
t1.Start();
t2.Start();
// 2개의 쓰레드 실행완료까지 대기
t1.Join();
t2.Join();
// 메인쓰레드에서 뮤텍스 사용
using (Mutex m = new Mutex(false, "MutexName1"))
{
// 뮤텍스를 취득하기 위해 10 ms 대기
if (m.WaitOne(10))
{
// 뮤텍스 취득후 MyList 사용
MyClass.MyList.Add(30);
}
else
{
Console.WriteLine("Cannot acquire mutex");
}
}
MyClass.ShowList();
}
}
public class MyClass
{
// MutexName1 이라는 뮤텍스 생성
private static Mutex mtx = new Mutex(false, "MutexName1");
// 데이타 멤버
public static List<int> MyList = new List<int>();
// 데이타를 리스트에 추가
public static void AddList(int val)
{
// 먼저 뮤텍스를 취득할 때까지 대기
mtx.WaitOne();
// 뮤텍스 취득후 실행 블럭
MyList.Add(val);
// 뮤텍스 해제
mtx.ReleaseMutex();
}
// 리스트 출력
public static void ShowList()
{
MyList.ForEach(p => Console.WriteLine(p));
}
}
}
using System.Threading;
using System.Collections.Generic;
namespace MultiThrdApp
{
class Program
{
static void Main(string[] args)
{
// 2개의 쓰레드 실행
Thread t1 = new Thread(() => MyClass.AddList(10));
Thread t2 = new Thread(() => MyClass.AddList(20));
t1.Start();
t2.Start();
// 2개의 쓰레드 실행완료까지 대기
t1.Join();
t2.Join();
// 메인쓰레드에서 뮤텍스 사용
using (Mutex m = new Mutex(false, "MutexName1"))
{
// 뮤텍스를 취득하기 위해 10 ms 대기
if (m.WaitOne(10))
{
// 뮤텍스 취득후 MyList 사용
MyClass.MyList.Add(30);
}
else
{
Console.WriteLine("Cannot acquire mutex");
}
}
MyClass.ShowList();
}
}
public class MyClass
{
// MutexName1 이라는 뮤텍스 생성
private static Mutex mtx = new Mutex(false, "MutexName1");
// 데이타 멤버
public static List<int> MyList = new List<int>();
// 데이타를 리스트에 추가
public static void AddList(int val)
{
// 먼저 뮤텍스를 취득할 때까지 대기
mtx.WaitOne();
// 뮤텍스 취득후 실행 블럭
MyList.Add(val);
// 뮤텍스 해제
mtx.ReleaseMutex();
}
// 리스트 출력
public static void ShowList()
{
MyList.ForEach(p => Console.WriteLine(p));
}
}
}
프로세스간 Mutex 활용
Mutex 활용에 적합한 예로서 흔히 한 머신 내에서 오직 한 응용프로그램(Application)만이 실행되도록 하는 테크닉을 든다. 한 컴퓨터 내 한 프로세스만 뜨게 하기 위해 고유의 Mutex명을 지정할 필요가 있는데, 일반적으로 이를 위해 GUID (globally unique identifier)를 사용한다. 처음 프로세스가 먼저 Mutex를 획득하면 다른 프로세스는 Mutex를 획득할 수 없기 때문에 오직 하나의 프로그램만 머신 내에서 실행되는 것이다.
예제
class Program
{
static void Main()
{
// Unique한 뮤텍스명을 위해 주로 GUID를 사용한다.
string mtxName = "60C3D9CA-5957-41B2-9B6D-419DC9BE77DF";
// 뮤텍스명으로 뮤텍스 객체 생성
// 만약 뮤텍스를 얻으면, createdNew = true
bool createdNew;
Mutex mtx = new Mutex(true, mtxName, out createdNew);
// 뮤텍스를 얻지 못하면 에러
if (!createdNew)
{
Console.WriteLine("에러: 프로그램 이미 실행중");
return;
}
// 성공하면 본 프로그램 실행
MyApp.Launch();
}
}
{
static void Main()
{
// Unique한 뮤텍스명을 위해 주로 GUID를 사용한다.
string mtxName = "60C3D9CA-5957-41B2-9B6D-419DC9BE77DF";
// 뮤텍스명으로 뮤텍스 객체 생성
// 만약 뮤텍스를 얻으면, createdNew = true
bool createdNew;
Mutex mtx = new Mutex(true, mtxName, out createdNew);
// 뮤텍스를 얻지 못하면 에러
if (!createdNew)
{
Console.WriteLine("에러: 프로그램 이미 실행중");
return;
}
// 성공하면 본 프로그램 실행
MyApp.Launch();
}
}