1. ๋“ค์–ด๊ฐ€๋ฉฐ

๊ฒฝํ•ฉ์กฐ๊ฑด์—์„œ๋Š” lock ํ‚ค์›Œ๋“œ๋กœ ๋ง‰์•„๋ฒ„๋ฆฌ๋ฉด ๋œ๋‹ค๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ฒŒ์ž„์—์„œ๋Š” ์„ฑ๋Šฅ์ด ์ƒ๋ช…์ด๋ผ ๋ชจ๋“  ์ ‘๊ทผ์„ ๋ง‰๋Š” ๊ฑด ๋‚ญ๋น„์ผ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์•ˆ์ „ํ•œ๋ฐ, ๊ตณ์ด ํ•œ ์ค„์”ฉ ์ค„ ์„ธ์šฐ๊ฒŒ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๊ทธ๋ž˜์„œ ๋“ฑ์žฅํ•˜๋Š” ๊ฒŒ Read-Write Lock์ด๋‹ค.

  • Read๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๋ช… OK

  • Write๋Š” ์˜ค์ง ํ•œ ๋ช…๋งŒ, ๋…์ !

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋กœ์ง์ด์žˆ๋Š”๋ฐ Read๋กœ์ง์ด 99.999%, Write๋กœ์ง์ด 0.0001%๋กœ ๋ฐœ์ƒํ•œ๋‹ค ๊ฐ€์ •ํ•œ๋‹ค ๊ทธ๋Ÿฌ๋ฉด Read๋งŒ ์ฃผ๊ตฌ์žฅ์ฐฝํ•˜๋Š”๋ฐ ๊ตณ์ด lock์„ ๊ณ„์†ํ•ด์„œ ์“ธํ•„์š”๊ฐ€ ์—†๋‹ค ์„ฑ๋Šฅ์˜ ์ด์ ์„ ์ฑ™๊ธฐ๋ ค๋ฉด writeํ• ๋•Œ๋งŒ read๋„ lock์— ๊ฑธ๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•˜๋ฉด ์„ฑ๋Šฅ์ ์œผ๋กœ ์ด๋“์„ ๋ณด๊ฒŒ๋œ๋‹ค

์ฆ‰, **Read-Write Lock์€ โ€œ์ฝ์„ ๋• ์ž์œ ๋กญ๊ฒŒ, ์“ธ ๋• ๋…์ ์ ์œผ๋กœโ€**๋ผ๋Š” ๊ทœ์น™์œผ๋กœ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ์„ ๋ชจ๋‘ ์ฑ™๊ธธ ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋‹ค.


2. Read-Write Lock ๊ธฐ๋ณธ ๊ฐœ๋…

  • Read Lock:
    ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” ๊ฒƒ์€ ์•ˆ์ „ํ•˜๋ฏ€๋กœ, ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ๋™์‹œ์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Write Lock:
    ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ๋Š” ๋‹จ ํ•œ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ œ์•ฝ:

    • ์“ฐ๋Š” ๋™์•ˆ์—๋Š” ์•„๋ฌด๋„ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์—†์Œ.

    • ์ฝ๋Š” ์ค‘์—๋Š” ๋‹ค๋ฅธ ์ฝ๊ธฐ ์Šค๋ ˆ๋“œ๋Š” ํ—ˆ์šฉ, ํ•˜์ง€๋งŒ ์“ฐ๊ธฐ๋Š” ๋ถˆ๊ฐ€๋Šฅ.

    • ์žฌ๊ท€์  ๋ฝ(Recursive Lock) ์ง€์› ์—ฌ๋ถ€๋Š” ๊ตฌํ˜„์— ๋”ฐ๋ผ ๋‹ค๋ฆ„.


3. ๊ตฌํ˜„ ์•„์ด๋””์–ด

3.1 Flag ๊ตฌ์กฐ

๋ฝ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด 32๋น„ํŠธ int ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

[Unused(1bit)] [WriteThreadId(15bit)] [ReadCount(16bit)]

  • ReadCount (ํ•˜์œ„ 16๋น„ํŠธ) : ํ˜„์žฌ ๋ช‡ ๊ฐœ์˜ Reader๊ฐ€ ์ ‘๊ทผ ์ค‘์ธ์ง€ ์ €์žฅ

  • WriteThreadId (์ค‘๊ฐ„ 15๋น„ํŠธ) : WriteLock์„ ์žก์€ Thread ID ์ €์žฅ

  • Unused (์ƒ์œ„ 1๋น„ํŠธ) : ์˜ˆ๋น„ ๋น„ํŠธ(์ถ”ํ›„ ๊ธฐ๋Šฅ ํ™•์žฅ์šฉ)


//๋ณ€์ˆ˜ ์†Œ๊ฐœ

        const int EMPTY_FLAG = 0x00000000;
        const int WRITE_MASK = 0x7FFF0000;
        const int READ_MASK = 0x0000FFFF;
        const int MAX_SPIN_COUNT = 5000;

        // [Unused(1 bit)]    [WriteThreadId(15 bit)]    [ReadCount(16 bit)]

        // ReadCount -> ์šฐ๋ฆฌ๊ฐ€ ReadLockํš๋“ํ•˜๋ฉด ์—ฌ๋Ÿฌ์• ๋“ค์ด Readํ• ์ˆ˜์žˆ์œผ๋‹ˆ ์นด์šดํŒ…ํ•˜๋Š”๊ฑฐ๊ณ 
        // Write -> ํ•œ๋ฒˆ์— ํ•œ ์Šค๋ ˆ๋“œ๋งŒ ํš๋“ํ• ์ˆ˜์žˆ๋‹ค ๊ทธ์นœ๊ตฌ๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ id์ €์žฅ
        int flag = EMPTY_FLAG;

        //ํ”Œ๋ž˜๊ทธ๊ฐ€ ํ•„์š”์—†๋Š”์ด์œ  
        //๋ˆ„๊ตฐ๊ฐ€๊ฐ€ write๋ฅผ ์žก์•˜๋‹ค๋Š”๊ฑด ๋‹ค๋ฅธ์• ๋Š”์—†๋‹ค ์˜ค์ง ํ•œ๋†ˆ๋งŒ ์žก๋Š”๊ฒƒ
        int writeCount = 0;

๐Ÿ‘‰ ์žฅ์ : int ํ•˜๋‚˜๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด Interlocked.CompareExchange ๊ฐ™์€ ์›์ž์  ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3.2 Write Lock

public void WriteLock()
{
    // ์žฌ๊ท€ ๋ฝ
    // ๋™์ผ ์“ฐ๋ ˆ๋“œ๊ฐ€ writeLock์„ ์ด๋ฏธ ํš๋“ํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
    int lockThreadId = (flag & WRITE_MASK) >> 16;
    if (Thread.CurrentThread.ManagedThreadId == lockThreadId)
    {
        writeCount++;
        return;
    }
 
 
    //----------------------------------------
 
    //์•„๋ฌด๋„ WriteLock or ReadLock์„ ํš๋“ํ•˜๊ณ  ์žˆ์ง€ ์•Š์„ ๋•Œ, ๊ฒฝํ•ฉํ•ด์„œ ์†Œ์œ ๊ถŒ์„ ์–ป๋Š”๋‹ค.
 
    // Thread.CurrentThread.ManagedThreadId == ๋ณธ์ธ ์Šค๋ ˆ๋“œ ์•„์ด๋””
    // << 16 ํ•ด์ฃผ๋Š” ์ด์œ  WRTIE_MASK๊ฐ€ 16๋น„ํŠธ์ดํ›„๋ถ€ํ„ฐ ๊ฐ’์„์“ฐ๊ธฐ์— ๋ฐ€์–ด์ฃผ๋Š”๊ฒƒ
    // & ์—ฐ์‚ฐ์„ ํ†ตํ•ด์„œ WRITE_MASK ๊ฐ’์ด ์•„๋‹Œ๊ฒƒ์„ ๋‹ค ๋ฐ€์–ด์ค€๋‹ค ํ˜น์‹œ ๋ชจ๋ฅด๋‹ˆ
 
    // ๋‚ด ์Šค๋ ˆ๋“œ ์•„์ด๋””๋งŒ ๋น„ํŠธ์— ๋“ค์–ด๊ฐ€๊ธธ ์›ํ•˜๋‹ˆ desired๊ฐ€ ๋œ๊ฒƒ
    int desired = (Thread.CurrentThread.ManagedThreadId << 16) & WRITE_MASK;
    while(true)
    {
        for(int i =0; i < MAX_SPIN_COUNT; i++)
        {
            if (EMPTY_FLAG == Interlocked.CompareExchange(ref flag, desired, EMPTY_FLAG))
            {
                writeCount = 1;
                return;
            }
        }
 
        Thread.Yield();
    }
}
  • ์žฌ๊ท€ ๋ฝ ํ—ˆ์šฉ: ๋™์ผ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ WriteLock์„ ์žก์„ ์ˆ˜ ์žˆ์Œ.

  • ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์“ฐ๊ณ  ์žˆ๊ฑฐ๋‚˜ ์ฝ๊ณ  ์žˆ์œผ๋ฉด ์‹คํŒจ โ†’ ์Šคํ•€ ํ›„ ์žฌ์‹œ๋„.


3.3 Read Lock

public void ReadLock()
{
    //@@write@@๊ฐ€ ์ด๋ฏธ ์žก๊ณ ์žˆ์„๋•Œ๋งŒ readCount๋ฅผ ๋Š˜๋ฆฌ๋Š”๊ฒƒ
    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;
 
        }
 
        Thread.Yield();
    }
}
 
 
 
 
  • ํ•ต์‹ฌ: expected = flag & READ_MASK

    • ๋ผ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์ƒ์œ„ 15๋น„ํŠธ๊ฐ€ ์ฑ„์›Œ์ ธ ์žˆ์–ด flag != expected โ†’ CAS ์‹คํŒจ โ†’ ์ฝ๊ธฐ ์ฐจ๋‹จ

    • ๋ผ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด flag == expected โ†’ CAS ์„ฑ๊ณต โ†’ ReadCount +1

  • ์—ฌ๋Ÿฌ Reader๊ฐ€ ๋™์‹œ์— ๋“ค์–ด์™€๋„ CAS๋กœ ์›์ž์  ์ฆ๊ฐ€ ๋ณด์žฅ.


3.4 Unlock

public void WriteUnLock()
{
    int lockCount = --writeCount;
    if (lockCount == 0)
        Interlocked.Exchange(ref flag, EMPTY_FLAG);
}
 
public void ReadUnLock()
{
    Interlocked.Decrement(ref flag);
}
 
  • Write๋Š” ์žฌ๊ท€ ํšŸ์ˆ˜๋ฅผ ์ฒดํฌํ•˜๊ณ  0์ด ๋˜๋ฉด ์™„์ „ํžˆ ํ•ด์ œ.

  • Read๋Š” ๋‹จ์ˆœํžˆ ์นด์šดํŠธ ๊ฐ์†Œ.


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

static volatile int count = 0;
static Lock _lock = new Lock();
 
static void Main(string[] args)
{
    Task t1 = new Task(() =>
    {
        for (int i = 0; i < 100000; ++i)
        {
            _lock.ReadLock();
            count++;
            _lock.ReadUnLock();
        }
    });
 
    Task t2 = new Task(() =>
    {
        for (int i = 0; i < 100000; ++i)
        {
            _lock.ReadLock();
            count--;
            _lock.ReadUnLock();
        }
    });
 
    t1.Start();
    t2.Start();
 
    Task.WaitAll(t1, t2);
 
    Console.WriteLine(count);
}
 

5. ์ •๋ฆฌ

  • ์ผ๋ฐ˜ ๋ฝ : ํ™”์žฅ์‹ค ์—ด์‡  1๊ฐœ. ๋ˆ„๊ตฌ๋“  1๋ช…๋งŒ ๋“ค์–ด๊ฐ€๊ณ , ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ.

  • Read-Write ๋ฝ :

    • ์ผ๋ฐ˜์ธ์€ ์ฝ๊ธฐ โ†’ ์—ฌ๋Ÿฌ ๋ช… ๋™์‹œ์— ํ™”์žฅ์‹ค ๊ตฌ๊ฒฝ ๊ฐ€๋Šฅ

    • VIP๋Š” ์“ฐ๊ธฐ โ†’ VIP๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ๋ฌธ์„ ๊ฑธ์–ด ์ž ๊ทธ๊ณ  ํ˜ผ์ž๋งŒ ์‚ฌ์šฉ

    • VIP๊ฐ€ ์—†์„ ๋•Œ๋Š” ๋งˆ์น˜ ๋ฝ์ด ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ž์œ ๋กญ๊ฒŒ ์ž…์žฅ


6. ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๋Š” flag & READ_MASK ์ •๋ฆฌ

๐Ÿ‘พ์ž ์ƒ๊ฐํ•ด๋ณด์ž flag & READ_MASK๋ฅผ ํ•œ๋‹ค์น˜์ž

  1. ๋งŒ์•ฝ ๋ˆ„๊ตฐ๊ฐ€ WRITE๋ฅผ ํ•ด์„œ ์•ž์ชฝ 0x7FFF0000๋ถ€๋ถ„์ด ๋ณ€๊ฒฝ๋œ ์ƒํƒœ๋ผ๊ณ  ๊ฐ€์ •
  2. ๊ทธ๋Ÿผ ํ˜„์žฌ flag๋Š” 0x32CF0000์ด ๋˜์–ด์žˆ๋‹ค๊ณ  ๊ฐ€์ •
  3. ํ˜„์žฌ ์—ฐ์‚ฐํ•˜๊ณ ์žˆ๋Š” ๋ถ€๋ถ„์€ READ_MASK์˜ ๋ถ€๋ถ„ ์ฆ‰ 0x0000FFFF์ด๋ถ€๋ถ„์„ ์—ฐ์‚ฐ์ค‘์ด๋‹ค
  4. WRITE๊ฐ€์žˆ๋Š”์ƒํƒœ expected = 0x32CF0000 & 0000FFFF ์„ํ•˜๋ฉด ๊ฐ’์ด ์–ด๋–ป๊ฒŒ๋‚˜์˜ฌ๊นŒ?
  5. expected = 0x00000000์ด ๋‚˜์˜จ๋‹ค (์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์˜๋„๋œ๊ฒŒ ๋งž๋‹ค RAED_MASK๋งŒ ์ฒดํฌํ• ๊ฑฐ์ด๊ธฐ์—)
  6. !!์—ฌ๊ธฐ์„œ ์ค‘์š”!!
  7. CompareExchange ์—ฌ๊ธฐ์„œ๋Š” expected(0x00000000์ด) == flag(0x32CF0000)๊ฐ€ ๊ฐ™์€์ง€ ๋ฌผ์–ด๋ณด๋Š”๊ฒƒ
  8. flag๊ฐ€ 0x0000000์ด๋ƒ? ์•„๋‹ˆ๋‹ค! write๊ฐ€ ๋ฝ์„ ์žก๊ณ ์žˆ์–ด์„œ ์žˆ์–ด์„œ 0x32CF0000๋‹ค!
  9. ๊ทธ๋ž˜์„œ ์‹คํŒจ๋ฅผ ํ•˜๊ฒŒ๋œ๋‹ค! !! ๊ฒฐ๋ก : WRITEํ•˜๋Š”๋™์•ˆ RAED๋ฅผ ๋ชปํ•˜๊ฒŒ ํ•˜๋ ค๋Š”๊ฒƒ

๐Ÿ‘พ๋‹ค์Œ๋‹จ๊ณ„ READ๊ฒฝํ•ฉ ์กฐ๊ฑด

  1. RAEDํ•˜๋ ค๋Š” ๋‘ ์Šค๋ ˆ๋“œ์˜ ๊ฒฝํ•ฉ ์ƒํƒœ๋ฅผ ์›ํ™œํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  ์นด์šดํŒ… ๋ฐฉ์‹
  2. int expected = (flag & READ_MASK) ๋‚ด๊ฐ€ ์›ํ•˜๋Š”๊ฐ’์„ ๊ณ„์‚ฐํ•œ๋‹ค
  3. ๋‹ค๋ฅธ์Šค๋ ˆ๋“œ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ํ•œ๋‹ค
  4. ๋„์ค‘์— ๋‹ค๋ฅธ์Šค๋ ˆ๋“œ๋„ (flag & READ_MASK)์—ฐ์‚ฐ์„ ํ•˜๊ฒŒ๋œ๋‹ค
  5. ๊ทธ๋Ÿผ ์ฒซ๋ฒˆ์งธ ์Šค๋ ˆ๋“œ์˜ expected๊ฐ’๊ณผ ๋‘๋ฒˆ์งธ ์Šค๋ ˆ๋“œ์˜ expected ๊ฐ’์ด ๊ฐ™๋‹ค
  6. ๊ทธ๋Ÿผ ๋‘๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋จผ์ € CompareExchange ํ•œ๋‹ค์น˜๋ฉด ๋‘๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๋Š” ํ†ต๊ณผํ•œ๋‹ค
  7. ๋‹ค์Œ์— ์ฒซ๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ํ•œ๋‹ค.
  8. ๊ทผ๋Œ€ ๋‚ด๊ฐ€ ์˜ˆ์ƒํ–ˆ๋˜ flag๊ฐ€ expected ๊ฐ’๊ณผ ๋‹ค๋ฅด๋‹ค ๊ทธ๋Ÿฌ๋ฉด ํ•œ๋ฒˆ ๋” ์ˆœํšŒ๋ฅผ ํ•˜๊ฒŒ๋œ๋‹ค
  9. ๋‹ค์‹œ ๋Œ์•„์™€์„œ (flag & READ_MASK); ํ•˜๊ฒŒ๋˜๊ณ  ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ํ•˜๊ฒŒ๋˜๋„ ๋ฌธ์ œ๊ฐ€์—†๋‹ค
  10. ์™œ๋ƒ? ์ง€๊ธˆ ๊ธฐ๋‹ค๋ฆฌ๊ณ ์žˆ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ์—†๊ธฐ๋•Œ๋ฌธ์ด๋‹ค.
  11. ๊ทธ๋ž˜์„œ ์ฒซ๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๋„ ์„ฑ๊ณตํ•˜๊ฒŒ๋˜๋ฉด์„œ ๋ฝ์„ ์–ป๊ฒŒ๋œ๋‹ค