반응형
인프런 - Rookies님의 강의
https://www.inflearn.com/course/%EC%9C%A0%EB%8B%88%ED%8B%B0-mmorpg-%EA%B0%9C%EB%B0%9C-part4
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 - 인프런 | 강의
네트워크/멀티쓰레드/운영체제 등 핵심 전공 지식을 공부하고 게임 서버를 바닥부터 만들어보면서 MMORPG 기술을 학습하는 강의입니다., MMORPG 개발에 필요한 모든 기술, C# + Unity로 Step By Step! 🕹
www.inflearn.com
// 재귀적 락을 허용할지 (No)
// 재귀적 락을 허용할지 (Yes) : WriteLock 상태에서 -> WriteLock 잡는거 OK / WriteLock 상태에서 -> ReadLock 잡는거 OK / ReadLock 상태에서 WriteLock NO
// 스핀락 정책 (5000번 -> Yield)
internal class Lock
{
// [Unused(1)] [WriteThreadId(15비트)] [ReadCount(16비트)]
// => int(32비트)
// Unused(1비트) : 32비트 중에 마지막 값은 음수가 될 수 있기 때문에 사용 안함
// 15비트를 WriteThreadId로 사용 / 16비트를 ReadCount로 사용 => 총 31비트만 사용
// => WRITE_MASK를 사용할 때 15비트 / READ_MASK를 사용할 때 16비트
// => ReadCount만 추출하고 싶을 때, READ_MASK를 씌워서 앞의 15비트는 0으로 밀어버리고 추출
// => WriteCount만 추출하고 싶을 때, WRITE_MASK를 씌워서 뒤의 16비트는 0으로 밀어버리고 추출
const int EMPTY_FLAG = 0x00000000;
const int WRITE_MASK = 0x7FFF0000;
const int READ_MASK = 0x0000FFF;
const int MAX_SPIN_COUNT = 5000;
int _flag = EMPTY_FLAG;
int _writeCount = 0;
public void WriteLock()
{
// 동일 쓰레드가 WriteLock을 이미 획득하고 있는지 확인
int lockThreadId = (_flag & WRITE_MASK) >> 16;
if(Thread.CurrentThread.ManagedThreadId == lockThreadId)
{
_writeCount++;
return;
}
// 아무도 WriteLock or ReadLock을 획득하고 있지 않을 때, 경합해서 소유권을 얻는다
// ManagedThreadId : 1부터 쭉 늘어나는 숫자
// 16비트 만큼 밀어줌
// & WRITE_MASK : WriteThreadId를 제외한 나머지 부분은 0으로 밀어줌
int 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;
}
// ==
// if (_flag == EMPTY_FLAG)
// _flag = desired;
}
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;
// ==
//if ((_flag & WRITE_MASK) == 0)
//{
// _flag = _flag + 1;
// return;
//}
}
Thread.Yield();
}
}
public void ReadUnlock()
{
Interlocked.Decrement(ref _flag);
}
}
반응형
'C# > C# 서버' 카테고리의 다른 글
[C#/서버] 기초 소켓 프로그래밍 (0) | 2023.08.22 |
---|---|
[C#/서버] AutoResetEvent / ManualResetEvent (0) | 2023.08.20 |
[C#/서버] SpinLock (0) | 2023.08.18 |
[C#/서버] 메모리 배리어 (0) | 2023.08.16 |
[C#/서버] 캐시 이론 (0) | 2023.08.16 |