SpinLock ๊ฐ์ ์ ์ํ Sleep ๋ฐ Yield ๊ธฐ๋ฐ Lock ๊ตฌํ๊ณผ OS ๋ ๋ฒจ ์ค์ผ์ค๋ง/๋ฌธ๋งฅ ๊ตํ ๊ตฌ์กฐ์ ์ค์ ์ดํด
์ด ๊ธ์ ๊ธฐ์กด SpinLock ๋ฐฉ์์ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด sleep_for, yield๋ฅผ ํ์ฉํ Lock ๋๊ธฐ ์ ๋ต์ ์ ์ํ๋ค. CPU ์์์ ๋ญ๋นํ์ง ์์ผ๋ฉด์๋ ์ปค๋๊ณผ์ ํ์กฐ๋ฅผ ํตํด ํจ์จ์ ์ผ๋ก ์ฌ์ง์
๊ฐ๋ฅํ Lock์ ๊ตฌํํ๋ฉฐ, ์ด ๊ณผ์ ์์ ๋ฐ์ํ๋ system call, context switching, time slice ๊ฐ๋
์ OS ๊ด์ ์์ ์์ ํ๊ฒ ์ค๋ช
ํ๋ค.
while (_locked) ๋ฃจํ๋ฅผ ๊ณ์ ๋๋ฉฐ Lock์ ์๋ โ ๋ฝ์ ๋ชป ์ป๋ ๋์์๋ CPU ์ ์ sleep_for() ๋๋ yield()๋ก ๊ตฌํ๋๋ฉฐ ์คํ๊ถ์ ์ปค๋์ ๋ฐํsleep, yield, system call์ ๋ชจ๋ ์๋ฐ์ ๋ฌธ๋งฅ ๊ตํ์ ์ ๋ฐ| ์ฉ์ด | ์๋ฏธ |
|---|---|
| SpinLock | ๋ฝ์ ์ป์ ๋๊น์ง ๋ฌดํ ๋ฃจํ ๋๋ฉฐ ๊ธฐ๋ค๋ฆฌ๋ ๋ฐฉ์ |
| sleep_for(nms) | ์ง์ ํ ์๊ฐ ๋์ ์ค๋ ๋๋ฅผ block ์ํ๋ก ๋ง๋ค๊ณ ์ปค๋์ ์คํ๊ถ์ ๋๊น |
| yield() | ํ์ฌ ์ค๋ ๋๊ฐ ์คํ๊ถ์ ๋ฐ๋ฉํ๊ณ ์ค๋น ํ๋ก ์ด๋ (sleep_for(0ms)์ ๋์ผ ํจ๊ณผ) |
| Time Slice | OS๊ฐ ์ค๋ ๋์๊ฒ ์ค CPU ์ฌ์ฉ ์๊ฐ |
| Context Switching | ์คํ ์ค์ธ ์ค๋ ๋๋ฅผ ์ค๋จํ๊ณ ๋ค๋ฅธ ์ค๋ ๋๋ก ์ ํ |
| System Call | ์ ์ ๋ชจ๋์์ ์ปค๋ ๊ธฐ๋ฅ ์์ฒญ ์ ์ฌ์ฉํ๋ ์ธํฐํ์ด์ค |
class SpinLock
{
public:
void lock()
{
bool expected = false;
bool desired = true;
while (_locked.compare_exchange_strong(expected, desired) == false)
{
expected = false;
// ์ด ์ค๋ ๋๋ ๋ฝ์ ๋ชป ์ป์์ผ๋ ์คํ๊ถ์ ์ปค๋์๊ฒ ๋ฐ๋ฉ
this_thread::sleep_for(0ms); // ๋๋ this_thread::yield();
}
}
void unlock()
{
_locked.store(false); // ๋ฝ ํด์
}
private:
atomic<bool> _locked = false;
};
compare_exchange_strong()๋ CAS(Compare-And-Swap) ์ฐ์ฐ์ผ๋ก Lock์ ์ป๋๋คexpected๋ ์ฐธ์กฐ๋ก ์ ๋ฌ๋๊ธฐ ๋๋ฌธ์ false๋ก ๋ค์ ์ด๊ธฐํํด์ผ ํ๋คsleep_for(0ms) ๋๋ yield()๋ฅผ ํตํด ์ค๋ ๋๋ ์๋ฐ์ ์ผ๋ก ์คํ๊ถ์ ์ปค๋์๊ฒ ๋๊ธด๋คint32 sum = 0;
SpinLock spinLock;
void Add()
{
for (int32 i = 0; i < 100000; i++)
{
lock_guard<SpinLock> guard(spinLock);
sum++;
}
}
void Sub()
{
for (int32 i = 0; i < 100000; i++)
{
lock_guard<SpinLock> guard(spinLock);
sum--;
}
}
int main()
{
thread t1(Add);
thread t2(Sub);
t1.join();
t2.join();
cout << sum << endl; // ํญ์ 0์ด ๋์ด์ผ ์ ํํ ๋๊ธฐํ๋จ
}
lock_guard๋ lock()๊ณผ unlock()์ ์๋์ผ๋ก ํธ์ถํ๋ RAII ๊ฐ์ฒดsleep์ ์ผ๋จ ์๋ฆฌ๋ก ๋์๊ฐ๋ค๊ฐ ๋ค์ ์ค๋ ์ ๋ต (๋๋ค ๋ฉํ)cout, sleep, ์
์ถ๋ ฅ ๋ฑ์ ๋ชจ๋ ์ปค๋ ๋ฆฌ์์ค ์์ฒญ โ system call ๋ฐ์sleep์ ๋๊ธฐ ์ํ๋ก ๋ง๋ค๊ณ , ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ค๋น ์ํ๋ก ๋ณต๊ทyield๋ ํ์ฌ ํ์ ์ฌ๋ผ์ด์ค๋ฅผ ๋ฐ๋ฉํ๊ณ ๋ฐ๋ก ์ค๋น ์ํ๋ก ์ด๋sleep_for์ yield๋ ์ปค๋ ์ง์
์ ์ ๋ํ๊ณ ์๋ฐ์ ๋ฌธ๋งฅ ๊ตํ์ ๋ฐ์์ํจ๋คsleep_for(0ms)์ yield()๋ ์๋ฏธ์ ๊ฑฐ์ ๊ฐ๋ค โ ์คํ๊ถ ํฌ๊ธฐcompare_exchange_strong์์ expected๋ ํญ์ ๋ฃจํ ๋ด์์ ์ด๊ธฐํํด์ผ ์ฌ์๋ ๊ฐ๋ฅ