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 ๋๋ฉด์ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์คํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
'๐ฅ๏ธ > C#' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[C#] LINQ์์ foreach๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฐ๋ฉด ์๋๋ ์ด์ (0) | 2023.10.12 |
---|---|
[C#] LINQ์ Single()์ ๋ํด์ (0) | 2023.10.12 |
[C#] ์ค๋ ๋(Thread) (0) | 2023.10.11 |
[C#] ๋ฆฌํ๋ ์ (Reflection): ๋์ ๋ฉ์๋ ์์ฑํ๊ธฐ (3) | 2023.10.11 |
[C#] ๋ฆฌํ๋ ์ (Reflection): ๋์ ์ธ์คํด์ค ์์ฑํ๊ธฐ (0) | 2023.10.10 |