C# Rookiss Part4 ๊ฒ์์๋ฒ : SpinLock
๐โโ๏ธSpinLock
ํ์ฅ์ค์ ์ฌ๋์ด ์๋ค๋ฉด ๋์ฌ ๋ ๊น์ง ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ค๊ฐ ๋ค์ด๊ฐ!
๐ช์์์ฑ์ ํ์
volatile bool _locked = false;
public void Acquire()
{
while (_locked)
{
// ๋๊ตฐ๊ฐ๊ฐ ํ์ด์ฃผ๊ธธ ๊ธฐ๋ค๋ฆฐ๋ค
}
// ๋ด๊บผ!
_locked = true;
}
public void Release()
{
_locked = false;
}
์๋ฌผ์ ๋ฅผ ๊ฑธ๊ณ ๋ค์ด๊ฐ ์ ๊ธ์ด ํ๋ฆฌ๊ธฐ๊น์ง ๊ธฐ๋ค๋ฆฌ๊ณ ๋ด๊ฐ ๋ค์ด๊ฐ๋ฉด ์๋ฌผ์ ๋ก ์ ๊ทผ๋ค
์ฌ์ฉ์ ๋คํ๋ฉด ์๊ธ์ ํ๊ณ ๋๊ฐ๋ค
์ธ๋ป๋ณด๋ฉด ์คํ๋ฝ์ด ์ ๊ตฌํ๋๊ฒ ๊ฐ์ง๋ง ์ํ๋ ๊ฒฐ๊ณผ๋ ์๋์จ๋ค
- ์ด์
- ๋ฌธ์ ํ์ด์ฃผ๊ธธ ๊ธฐ๋ค๋ฆฌ๋ ๋ถ๋ถ๊ณผ ๋ฌธ์ ์ ๊ตฌ๋ ๋ถ๋ถ์ด ์์์ ์ผ๋ก ์ฒ๋ฆฌ ๋์ง ์์๊ธฐ ๋๋ฌธ
- ํ์ฅ์ค์ ๋๋ช ์ด ๋์์ ๋ค์ด๊ฐ์ ๋ฌธ์ ์ ๊ทธ๋ ์ํฉ์ด ๋ฐ์ํจ!
- ํ์ฅ์ค์ ๋ค์ด๊ฐ๊ณ ๋ฌธ์ ์ ๊ตฌ๋ ๊ฒ์ ์์์ ์ผ๋ก ์ฒ๋ฆฌ ํด์ผ๋๋ค!!
๐ชInterlocked.Exchange
volatile int _locked = 0;
public void Acquire()
{
while (true)
{
int original = Interlocked.Exchange(ref _locked, 1);
if (original == 0) // ํ์ฅ์ค์ ์ฌ๋์ด ์์๋ค๋ฉด original์ 0์ด๊ณ _locked์๋ 1์ด ๋ค์ด๊ฐ
break;
}
}
public void Release()
{
_locked = 0;
}
int original = Interlocked.Exchange(ref _locked, 1);
ํด์Interlocked.Exchange(ref _locked, 1)
์ _locked์ 1์ ๋์ ํ๋๊ฒ- original์ _locked์ 1์ ๋์ ํ๊ธฐ ์ ๋ค์ด์๋ ๊ฐ
- ํ์ฅ์ค์ ๋ค์ด๊ฐ๊ณ ๋ฌธ์ ์ ๊ทธ๋ ๊ฒ์ด ์์์ ์ผ๋ก ์ฒ๋ฆฌ!
original = _locked;
_locked = 1;
if (original == 0)
break;
์์์ ์ผ๋ก ์ฒ๋ฆฌ๋ ๋ถ๋ถ์ ํ์ด์ด๊ฒ
๐ชInterlocked.CompareExchange
- CAD Compare - And - Swap ์ฐ์ฐ
// CAD Compare - And - Swap ์ฐ์ฐ
int expected = 0;
int desired = 1;
if (Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
break;
if (Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
ํด์- _locked๊ฐ expected์ ๊ฐ์ผ๋ฉด desired๋ฅผ ๋์ ํ๋ผ
- ๋ฐํ๊ฐ์ _locked์ ๋ค์ด์๋๊ฐ
- ๋ฐํ๊ฐ(์ด์ ๊ฐ)์ด expected์ ๊ฐ์ผ๋ฉด~~
๊ฐ์ ๋น๊ตํ ๊ฐ์ผ๋ฉด ๊ฐ์ ๋ฐ๊พธ๋ ์ฐ์ฐ๋ฒ CAS์ฐ์ฐ! (Compare - And - Swap)
Interlocked.Exchange๋ณด๋ค ์์ฃผ ์ฌ์ฉ๋๋ค
๐ชInterlocked.CompareExchange์ ์ฌ์ฉํ ์ ์ฒด์ฝ๋
namespace ServerCore
{
class SpinLock
{
volatile int _locked = 0;
public void Acquire()
{
while (true)
{
// CAD Compare - And - Swap
int expected = 0;
int desired = 1;
if (Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
break;
}
}
public void Release()
{
_locked = 0;
}
}
class Program
{
static int _num = 0;
static SpinLock _lock = new SpinLock();
static void Thread_1()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread_2()
{
for (int i = 0; i < 100000; i++)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(_num);
}
}
}