For me
[Server] ReaderWriterLock 본문
ReaderWriterLock 구현
using System;
namespace ServerCore
{
// 재귀적 락 허용 => WriteLock -> WriteLock, WriteLock -> ReadLock (O), ReadLock -> WrtieLock (X)
// 스핀락 정책 (5000번 -> Yield)
public class Lock
{
private const int EMPTY_FLAG = 0x0000000;
private const int WRITE_MASK = 0x7FFF0000;
private const int READ_MASK = 0x0000FFFF;
private const int MAX_SPIN_COUNT = 5000;
// [Unused(1)] [WriteThreadId(15)] [ReadCount(16)]
private int _flag;
private int _writeCount = 0;
public void WriteLock()
{
// 동일 스레드가 WriteLock을 이미 획득하고 있는지 확인
int lockThreadId = (_flag & WRITE_MASK) >> 16;
if (Thread.CurrentThread.ManagedThreadId == lockThreadId)
{
_writeCount++;
return;
}
// 아무도 WriteLock or ReadLock을 획득하고 있지 않을 때 경합해서 소유권을 얻음
var desired = (Thread.CurrentThread.ManagedThreadId << 16) & WRITE_MASK;
while (true)
{
for (int i = 0; i < MAX_SPIN_COUNT; i++)
{
// 시도를 해서 성공하면 return
if (Interlocked.CompareExchange(ref _flag, desired, EMPTY_FLAG) == EMPTY_FLAG)
{
_writeCount = 1;
return;
}
}
Thread.Yield();
}
}
public void WriteUnlock()
{
int lockCount = --_writeCount;
if (lockCount == 0)
{
Interlocked.Exchange(ref _flag, EMPTY_FLAG);
}
}
public void ReadLock()
{
// 동일 스레드가 WriteLock을 이미 획득하고 있는지 확인
int lockThreadId = (_flag & WRITE_MASK) >> 16;
if (Thread.CurrentThread.ManagedThreadId == lockThreadId)
{
Interlocked.Increment(ref _flag);
return;
}
// 아무도 WriteLock을 획득하고 있지 않으면 ReadCount += 1
while (true)
{
for (int i = 0; i < MAX_SPIN_COUNT; i++)
{
int expected = _flag & READ_MASK;
if (Interlocked.CompareExchange(ref _flag, expected + 1, expected) == expected)
{
return;
}
Thread.Yield();
}
}
}
public void ReadUnlock()
{
Interlocked.Decrement(ref _flag);
}
}
}
'Server > Study' 카테고리의 다른 글
[Server] Socket (0) | 2023.05.01 |
---|---|
[Server] Thread Local Storage (0) | 2023.04.26 |
[Server] AutoResetEvent (0) | 2023.04.26 |
[Server] Context Switching (0) | 2023.04.26 |
[Server] Lock - 3 (SpinLock) (0) | 2023.04.26 |