πŸ–₯️/C#

[C#] μŠ€λ ˆλ“œμ˜ 크리티컬 μ„Ήμ…˜(Critical Section)

HanaV 2023. 10. 11. 16:00
728x90
public static void IncrementCounter()
{
    for (int i = 0; i < 100000; i++) {
        counter++; 
    }
}

μœ„ λ©”μ„œλ“œλŠ” counterμ΄λΌλŠ” λ³€μˆ˜λ₯Ό 100,000번 λ°˜λ³΅ν•΄μ„œ 1μ”© μ˜¬λ¦¬λŠ” μž‘μ—…μ„ ν•œλ‹€.
λ§Œμ•½ 이 counter λ³€μˆ˜λ₯Ό 같이 μ¦κ°€μ‹œν‚€λŠ” μŠ€λ ˆλ“œκ°€ 같이 μ‹œμž‘λ˜μ—ˆλ‹€κ³  ν•΄λ³΄μž.

Thread t1 = new Thread(IncrementCounter);
Thread t2 = new Thread(IncrementCounter);

t1.Start();
t2.Start();

t1.Join();
t2.Join();

t1 μŠ€λ ˆλ“œλ„ 100,000, t2 μŠ€λ ˆλ“œλ„ 100,000을 μ˜¬λ €μ„œ countλŠ” 200,000이 λ˜μ–΄μ•Όν•  것 κ°™μ§€λ§Œ, μ‹€μ œλ‘œ μ‹€ν–‰μ‹œμΌœλ³΄λ©΄ 맀번 λ‹€λ₯΄κ²Œ λ‚˜μ˜€λŠ” 것을 λ³Ό 수 μžˆλ‹€.

μ™œ 이런 일이 μΌμ–΄λ‚ κΉŒ?

μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— counterλ₯Ό λ™μ‹œμ— μ¦κ°€μ‹œν‚€λ €κ³  μ‹œλ„ν•˜κΈ° λ•Œλ¬Έμ— 경쟁 μƒνƒœ(Race condition)κ°€ λ°œμƒν•˜κ²Œ λœλ‹€. 예λ₯Ό λ“€μ–΄ ν˜„μž¬ counter 값이 10이라면,

1. t1κ³Ό t2κ°€ ν˜„μž¬ counter 값을 10으둜 μ½λŠ”λ‹€.
2. t1이 counter 값을 11둜 μ¦κ°€μ‹œν‚€κ³  μ €μž₯ν•œλ‹€.
3. t2도 counter 값을 10으둜 μ•Œκ³ μžˆκΈ° λ•Œλ¬Έμ— 11을 λ‹€μ‹œ μ €μž₯ν•œλ‹€.

μ΄λ ‡κ²Œ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— 곡유 λ³€μˆ˜μ— μ ‘κ·Όν•˜κ³  μˆ˜μ •ν•˜λ €κ³  ν•  λ•Œ, 경쟁 μƒνƒœλ‘œ 인해 데이터 일관성이 깨질 수 μžˆλ‹€. 이λ₯Ό 막기 μœ„ν•΄ 크리티컬 μ„Ήμ…˜μ„ λ§Œλ“€μ–΄ μ‚¬μš©ν•œλ‹€.

 

 

 
 

크리티컬 μ„Ήμ…˜(Critical Section)

 

λ©€ν‹° μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ 곡유 μžμ›μ— λ™μ‹œμ— μ ‘κ·Όν•˜λŠ” 것을 μ œμ–΄ν•˜κ³  λ™κΈ°ν™”ν•˜λŠ” 데 μ‚¬μš©λ˜λŠ” μ½”λ“œ μ˜μ—­μ„ 크리티컬 μ„Ήμ…˜μ΄λΌκ³  ν•œλ‹€. 즉, ν•œ λ²ˆμ— ν•œ μŠ€λ ˆλ“œλ§Œ μ‚¬μš©ν•  수 μžˆλŠ” μ˜μ—­μ΄λ‹€.

lock ν‚€μ›Œλ“œ

크리티컬 μ„Ήμ…˜μ€ lock ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ κ°„λ‹¨ν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.
μœ„μ˜ μ˜ˆμ‹œμ—μ„œ lock을 ν•˜λ©΄ μ΄λ ‡κ²Œ λœλ‹€.

private static object lockObject = new object();

for (int i = 0; i < 100000; i++) {
    lock (lockObject) 
    {
        counter++; 
    }
}

이 λ•Œ, lock은 κΌ­ μ°Έμ‘°ν˜• 데이터 νƒ€μž…μœΌλ‘œ μ„ μ–Έν•΄μ€˜μ•Όν•œλ‹€. object, string λ‘˜ λ‹€ λœλ‹€.

이제 lock ν‚€μ›Œλ“œλ‘œ λ‘˜λŸ¬μŒ“μΈ counter λ³€μˆ˜κ°€ μ¦κ°€ν•˜λŠ” 뢀뢄은 크리티컬 μ„Ήμ…˜μ΄ λœλ‹€. 이 뢀뢄은 이제 ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œκ°€ 싀행될 λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ κ°œμž…ν•˜μ§€ λͺ»ν•œλ‹€.

κ²°κ³Ό λ˜ν•œ 200,000이 μž˜λ‚˜μ˜€λŠ” 것을 확인할 수 μžˆλ‹€.

 

Monitor 클래슀

Monitor ν΄λž˜μŠ€λŠ” lockκ³Ό λ™μΌν•œ 역할을 ν•˜λŠ” Monitor.Enter()κ³Ό Monitor.Exit()이 μžˆλ‹€. (사싀 lock이 이 λ©”μ„œλ“œ 두 κ°€μ§€λ‘œ 이루어져 μžˆλ‹€)

public static void IncrementCounter()
{
    for (int i = 0; i < 100000; i++) {
        Monitor.Enter(lockObject);
        counter++;
        Monitor.Exit(lockObject);
    }
}

Monitor ν΄λž˜μŠ€μ—λŠ” Monitor.Wait()κ³Ό Monitor.Pulse() λ©”μ„œλ“œλ„ μžˆλ‹€. 이 두 λ©”μ„œλ“œλŠ” 말 κ·ΈλŒ€λ‘œ μŠ€λ ˆλ“œλ₯Ό λŒ€κΈ°/μ‹€ν–‰ λŒ€κΈ°μƒνƒœλ‘œ ν•˜λŠ” λ©”μ„œλ“œμ΄λ‹€. 

public static void Sender()
{
    for (int i = 0; i < 3; i++) {
        lock (lockObject) {
            Console.WriteLine("Sender is typing a message...");
            Thread.Sleep(1000);

            message = "Message " + (i + 1);
            Console.WriteLine("Sender sent: " + message);
            Thread.Sleep(500);

            Console.WriteLine("Pulsing Receiver...");
            Monitor.Pulse(lockObject); Thread.Sleep(500);

            Console.WriteLine("Sender is waiting Receiver to receive the message...");
            Monitor.Wait(lockObject); Thread.Sleep(500);
        }
    }
}

public static void Receiver()
{
    for (int i = 0; i < 3; i++) {
        lock (lockObject) {
            Console.WriteLine("Receiver is waiting for a message...");
            Monitor.Wait(lockObject); Thread.Sleep(500);

            Console.WriteLine("Receiver received: " + message);
            Thread.Sleep(500);

            Console.WriteLine("Pulsing Sender...");
            Monitor.Pulse(lockObject); Thread.Sleep(500);
        }
    }
}

이 두 개λ₯Ό μŠ€λ ˆλ“œ 두 κ°œμ— 각각 μ‹€ν–‰μ‹œν‚€λ©΄,

Receiver is waiting for a message...
Sender is typing a message...
Sender sent: Message 1
Pulsing Receiver...
Sender is waiting Receiver to receive the message...
Receiver received: Message 1
Pulsing Sender...
Receiver is waiting for a message...
Sender is typing a message...
Sender sent: Message 2
Pulsing Receiver...
Sender is waiting Receiver to receive the message...
Receiver received: Message 2
Pulsing Sender...
Receiver is waiting for a message...
Sender is typing a message...
Sender sent: Message 3
Pulsing Receiver...
Sender is waiting Receiver to receive the message...
Receiver received: Message 3
Pulsing Sender...

μ΄λ ‡κ²Œ wait λ˜λ©΄μ„œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

728x90
λŒ“κΈ€μˆ˜0