레이스 컨디션 문제를 해결하기 위하여 사용
Interlocked.Increment(ref x);
Interlocked.Decrement(ref x);
Interlocked.Add(ref x, 10);
int origin = Interlocked.Exchange(ref x, 1);
int origin2 = Interlocked.CompareExchange(ref x, 1, 0); // CAS Compare-And-Swap
주로 정수형 데이터를 수정할 때 사용
static object key = new object();
static void TestThread1()
{
try
{
Monitor.Enter(key);
x++;
}
finally
{
Monitor.Exit(key);
}
}
Enter와 Exit의 짝을 항상 맞춰야 함
TryEnter 함수로 일정 시간동안 lock을 시도하는 함수를 사용할 수 있음
lock (key)
{
x++;
}
Monitor와 같지만 Enter, Exit을 신경쓰지 않아도 된다.
해당 구문을 빠져나올 시 자동으로 release
lock을 잡을 때까지 계속하여 시도함 (busy waiting)
context switching의 비용을 생각하여 계속 시도하는 것이 더 효율적일 수 있음
class CustomSpinLock
{
volatile int _lockCount = 0;
public void Acquire()
{
while (true)
{
if (Interlocked.CompareExchange(ref _lockCount, 1, 0) == 0)
{
return;
}
}
}
public void Release()
{
Interlocked.Exchange(ref _lockCount, 0);
}
}
C#에 기본적으로 구현 되어 있음
그러나 전혀 양보하지 않고 시도하는게 아니라 어느정도 시도 후 양보
static SpinLock _spinLock = new SpinLock();
static void TestThread1()
{
bool lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken);
x++;
}
finally
{
if (lockTaken)
{
_spinLock.Exit();
}
}
}
yield
lock 시도 후 스레드를 양보함
Thread.Sleep(1); // 1ms만큼 휴식하길 원하지만 시간이 어떻게될지는 os 마음
Thread.Sleep(0); // 스레드 우선순위를 계산하여 나와 순위가 같거나 높은 스레드에게 양보
Thread.Yield(); // 실행이 가능한 스레드에게 양보
커널에서 관리하는 lock을 이용하며 사용 가능하게 될 때
기다리고 있는 스레드들에게 이벤트 시그널을 날려줌
=> 커널까지 통신해야 해서 다른 lock과 비교적 속도가 느림
class EventLock
{
AutoResetEvent _lock = new AutoResetEvent(true);
// initial state: true 바로 사용 가능, false 바로 사용 불가능
public void Acquire()
{
_lock.WaitOne(); // AutoReset => _lock.Reset()을 한번에 실행
}
public void Release()
{
_lock.Set();
}
}
마찬가지로 커널을 이용한 동기화 변수로 스레드 id나 잠긴 회수등의 추가 정보를 가짐
멀티 프로세스에서 사용 가능
static Mutex _lock = new Mutex();
static void TestThread2()
{
for (int i = 0; i < 10000; i++)
{
_lock.WaitOne();
y++;
_lock.ReleaseMutex();
}
}
메모리의 read, write를 따로 지정하여 잠글 수 있음
writer가 없을 시 다수의 스레드가 메모리에 접근하여 read할 수 있음
static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
static void TestThread2()
{
for (int i = 0; i < 10000; i++)
{
_lock.EnterReadLock();
int temp = y + 1;
_lock.ExitReadLock();
}
}