์ˆ˜์—…


๐Ÿงต ์ฃผ์ œ

C++์—์„œ SpinLock์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ฉฐ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™”, atomic ์—ฐ์‚ฐ, compare_exchange_strong ํ•จ์ˆ˜์˜ ์˜๋ฏธ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์‹ค์ „ ์ฝ”๋“œ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ฒ• ํ•™์Šต


๐Ÿ“˜ ๊ฐœ๋…

โœ… SpinLock์ด๋ž€?

  • SpinLock์€ ๋ฝ์ด ํ’€๋ฆด ๋•Œ๊นŒ์ง€ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฝ์ด๋‹ค.
  • OS์—๊ฒŒ CPU๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ๊ณ„์† CPU๋ฅผ ์ ์œ ํ•œ ์ฑ„ ๋ฐ”์œ ๋Œ€๊ธฐ(busy waiting)๋ฅผ ํ•˜๋ฉฐ ๋ฝ์„ ์‹œ๋„ํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ lock/unlock ์‚ฌ์ดํด์ด ๋งค์šฐ ์งง๊ณ  ์ถฉ๋Œ์ด ์ ์€ ์ƒํ™ฉ์—์„œ ํšจ๊ณผ์ ์ด๋‹ค.
  • ๋ฐ˜๋ฉด, ๋ฝ์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋ฉด CPU๋ฅผ ๋ฌด์˜๋ฏธํ•˜๊ฒŒ ์†Œ๋ชจํ•˜๋ฏ€๋กœ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค.

โœ… SpinLock์˜ ์žฅ๋‹จ์ 

ํ•ญ๋ชฉ์žฅ์ ๋‹จ์ 
CPU ์‚ฌ์šฉ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์—†์œผ๋ฏ€๋กœ ๋น ๋ฆ„CPU ์ ์œ ์œจ์ด ๋งค์šฐ ๋†’์Œ
๋ฝ ๋Œ€๊ธฐ๋ฝ์ด ๊ธˆ๋ฐฉ ํ’€๋ฆด ๋•Œ ์ ํ•ฉ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋ฉด ์ „์ฒด ์‹œ์Šคํ…œ ์„ฑ๋Šฅ ํ•˜๋ฝ
๊ตฌ์กฐ๊ฐ„๋‹จํ•˜๊ณ  lightweight๋Œ€๊ธฐ ์ค‘ ๋‹ค๋ฅธ ์ž‘์—… ๋ถˆ๊ฐ€

โœ… ์™œ ๋ฉด์ ‘์—์„œ ์ž์ฃผ ๋‚˜์˜ฌ๊นŒ?

  • SpinLock์„ ๊ตฌํ˜„ํ•ด๋ณด๋ผ๊ณ  ํ•˜๋Š” ์ด์œ ๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™” ๊ฐœ๋…, atomic ์—ฐ์‚ฐ ์ดํ•ด๋„, ๋™๊ธฐํ™” ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ๋””๋ฒ„๊น… ๋Šฅ๋ ฅ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ.
  • ํŠนํžˆ compare_exchange_strong(CAS ์—ฐ์‚ฐ)์— ๋Œ€ํ•œ ์ดํ•ด ์—ฌ๋ถ€๋ฅผ ๋ณด๊ธฐ ์œ„ํ•จ.

๐Ÿ“š ์šฉ์–ด ์ •๋ฆฌ

์šฉ์–ด์„ค๋ช…
SpinLock๋ฝ์ด ํ’€๋ฆด ๋•Œ๊นŒ์ง€ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฝ
atomic๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์›์ž์„ฑ ๋ณด์žฅ์„ ์œ„ํ•œ ํƒ€์ž…
compare_exchange_strong์กฐ๊ฑด์ด ๋งž์œผ๋ฉด ๊ฐ’์„ ๋ฐ”๊พธ๋Š” CAS ๋ฐฉ์‹ ํ•จ์ˆ˜
volatile์ปดํŒŒ์ผ๋Ÿฌ ์ตœ์ ํ™”๋ฅผ ๋ง‰๋Š” ํ‚ค์›Œ๋“œ (ํ•˜์ง€๋งŒ ๋™๊ธฐํ™” ๋ณด์žฅ X)
context switching์Šค๋ ˆ๋“œ ์ „ํ™˜ ์‹œ ๋ ˆ์ง€์Šคํ„ฐ ๋“ฑ ์ƒํƒœ ์ €์žฅ/๋ณต์› ๋น„์šฉ

๐Ÿ’ป ์ฝ”๋“œ ๋ถ„์„

โŒ ์ž˜๋ชป๋œ SpinLock ๊ตฌํ˜„

class SpinLock
{
public:
    void lock()
    {
        while (_locked) { }
        _locked = true;
    }

    void unlock()
    {
        _locked = false;
    }

private:
    bool _locked = false;
};

๋ฌธ์ œ์ 

  • _locked๋Š” bool๋กœ ์„ ์–ธ๋˜์–ด ์›์ž์„ฑ ๋ณด์žฅ์ด ์•ˆ ๋จ โ†’ Race Condition ๋ฐœ์ƒ
  • while (_locked)๊ณผ _locked = true๊ฐ€ ๋ถ„๋ฆฌ๋œ ์—ฐ์‚ฐ โ†’ ๋™๊ธฐํ™” ์‹คํŒจ ๊ฐ€๋Šฅ
  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ตœ์ ํ™”๋ฅผ ํ•ด๋ฒ„๋ฆด ์ˆ˜๋„ ์žˆ์Œ โ†’ ์˜ˆ์ธก ๋ถˆ๊ฐ€ํ•œ ๋™์ž‘

โœ… ๊ฐœ์„ ๋œ SpinLock ๊ตฌํ˜„ (atomic + CAS)

class SpinLock
{
private:
    std::atomic<bool> _locked = false;

public:
    void lock()
    {
        bool expected = false;
        bool desired = true;

        while (_locked.compare_exchange_strong(expected, desired) == false)
        {
            expected = false; // ์ค‘์š”: ์ฐธ์กฐ๋กœ ์ „๋‹ฌ๋จ โ†’ ์‹คํŒจ ์‹œ ๋ณต๊ตฌ ํ•„์ˆ˜
        }
    }

    void unlock()
    {
        _locked.store(false);
    }
};

ํ•ต์‹ฌ ์„ค๋ช…

  • compare_exchange_strong(expected, desired)๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘:
if (_locked == expected) {
    _locked = desired;
    return true;
} else {
    expected = _locked;
    return false;
}
  • expected๋Š” ์ฐธ์กฐ๋กœ ์ „๋‹ฌ๋˜๋ฉฐ, ์‹คํŒจ ์‹œ ๋‚ด๋ถ€์—์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ๋‹ค์‹œ false๋กœ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ๋ฃจํ”„๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•จ

โœ… ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

int32 sum = 0;
SpinLock spinLock;

void Add()
{
    for (int32 i = 0; i < 100000; i++)
    {
        std::lock_guard<SpinLock> guard(spinLock);
        sum++;
    }
}

void Sub()
{
    for (int32 i = 0; i < 100000; i++)
    {
        std::lock_guard<SpinLock> guard(spinLock);
        sum--;
    }
}

int main()
{
    std::thread t1(Add);
    std::thread t2(Sub);

    t1.join();
    t2.join();

    std::cout << sum << std::endl; // ํ•ญ์ƒ 0 ์ถœ๋ ฅ๋ผ์•ผ ์„ฑ๊ณต
}

ํ•ต์‹ฌ ํฌ์ธํŠธ

  • std::lock_guard๋Š” lock()/unlock() ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์žˆ์œผ๋ฉด ๋™์ž‘ํ•จ
  • RAII ํŒจํ„ด์œผ๋กœ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ lock ์ž๋™ ํ•ด์ œ โ†’ ์•ˆ์ „ํ•œ ๊ตฌ์กฐ

๐ŸŽฏ ํ•ต์‹ฌ

  • SpinLock์€ ์งง์€ ๋ฝ ์ƒํ™ฉ์—์„œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ค„์ด๊ณ  ๋น ๋ฅด๊ฒŒ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ˆœ bool ๋ณ€์ˆ˜๋กœ๋Š” ์ ˆ๋Œ€ ์•ˆ์ „ํ•œ ๋ฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค โ†’ ๋ฐ˜๋“œ์‹œ std::atomic ์‚ฌ์šฉ.
  • compare_exchange_strong ํ•จ์ˆ˜์˜ expected ์ธ์ž๋Š” ์ฐธ์กฐ์ด๋ฏ€๋กœ, ๋ฃจํ”„๋งˆ๋‹ค expected = false๋กœ ์ดˆ๊ธฐํ™”ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
  • volatile์€ ์ตœ์ ํ™”๋งŒ ๋ง‰์„ ๋ฟ, ๋™๊ธฐํ™”๋‚˜ ์›์ž์„ฑ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Œ.
  • ์‹ค์ „์—์„œ๋Š” ๋ฝ์ด ์งง์„ ๊ฒฝ์šฐ์—๋งŒ SpinLock์„ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด mutex, condition_variable ๋“ฑ์˜ ๋Œ€์ฒด ๋„๊ตฌ ์‚ฌ์šฉ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค.

profile
๏งกๅฎถ๋„ค_๊ณต๋ถ€๋ฐฉ

0๊ฐœ์˜ ๋Œ“๊ธ€