방법1.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace GameServerCore
{
class SpinLock
{
volatile int _locked = 0;
public void Acquire()
{
while (true)
{
int original = Interlocked.Exchange(ref _locked, 1);
if (original == 0)
break;
}
}
public void Release()
{
_locked = 0;
}
}
class Program
{
static int _num = 0;
static SpinLock _lock = new SpinLock();
static void Main(string[] args)
{
Task t1 = new Task(Thread1);
Task t2 = new Task(Thread2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(_num);
}
static void Thread1()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread2()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
}
}
방법2. (권장되는 방법)
.CompareExchange()처럼 두 값을 비교해 같을 경우 어떤 값을 대입하는 연산을
CAS 혹은 Compare and Swap연산이라고 하며 C++에서도 함수로 존재한다.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace GameServerCore
{
class SpinLock
{
volatile int _locked = 0;
public void Acquire()
{
while (true)
{
int expected = 0;
int desired = 1;
// _locked == 0이면 _locked 에 1을 넣음.
// CompareExchange의 반환값은 _locked의 대입 전 값, 즉 원본값이라는 것에 유의
if (Interlocked.CompareExchange(ref _locked, desired, 0) == expected)
{
break;
}
}
}
public void Release()
{
_locked = 0;
}
}
class Program
{
static int _num = 0;
static SpinLock _lock = new SpinLock();
static void Main(string[] args)
{
Task t1 = new Task(Thread1);
Task t2 = new Task(Thread2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(_num);
}
static void Thread1()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread2()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
}
}
'networking' 카테고리의 다른 글
Game Traffic Analysis: An MMORPG Perspective Kuan-Ta Chen, Polly Huang, Chin-Lau (0) | 2023.10.24 |
---|---|
군복무 중 서버 개발 학습기록 (0) | 2022.03.09 |