ð ì€ë 죌ì ìž ê²œì ìíì ìíž ë°°ì ë ë©í°ì€ë ë ìžìë ë©í°íë¡ìžì€ììë ë°ìí ì ìë 묞ì ìŽì§ë§
ì ê° ë©í°ì€ë ëì ëíŽ ë°°ì°ë©° ì 늬í ëŽì©ìŒë¡, ë©í°ì€ë ëì ëíŽìë§ ì€ì ì ìŒë¡ ìžêžíìµëë€.
ì°©ì€ê° ììŒìêžž!
â ë©í°ì€ë ëë?
ìŽì êžìì ì€ë ëì ê°ë ì ìŽíŽëŽ€ìµëë€.
âïž íë¡ìžì€ / ì€ë ë ê°ë ì 늬
ð ììœíë¡ê·žëš: ìŽë ìì ì íêž° ìíŽ ì€íë ì ìë íìŒíë¡ìžì€: ë©ëªšëЬì ì¬ëŒê°ê³ , ìŽì첎ì ë¡ë¶í° CPU륌 í ë¹ë°ì ì€í ì€ìž íë¡ê·žëšì€ë ë: íë¡ìžì€ ëŽìì ë 늜ì ìŒë¡ ì€íëë
syleeblog.tistory.com
ë©í°ì€ë ëë íëì íë¡ìžì€ ìì ì¬ë¬ ê°ì ì€ë ëê° ìë ìí륌 ë§í©ëë€.
ìŠ, íëì íë¡ìžì€ ììì ë ê°ì§ ìŽìì ìì ì í ì ììµëë€.
í¬ë¡¬ìì ì¬ë¬ ì°œì ëì ê°ì ìì í ì ìë¯ìŽ
ë©í°ì€ë ë í겜ììë ì¬ë¬ ìì ì ëìì, ë 늜ì ìŒë¡ ìíí ì ìë€ë ì¥ì ìŽ ììµëë€.
ì륌 ë€ìŽ, 칎칎ì€í¡ìì íìŒì ì ì¡íë ë° ëª ìŽê° 걞늬Ʞë íì§ë§, ê·ž ìê° ëì ì¬ì©ìë ì ì¡ìŽ ëëꞰ륌 êž°ë€ëЬë ê² ìëëŒ ìë¡ìŽ í¡ì 볎ëŽë ë±ì ë€ë¥ž íëì ìì ë¡ê² í ì ììµëë€.
ëí ìë¡ ë³ê°ì ë©ëªšëЬ ê³µê°ì ê°ì§ë íë¡ìžì€ì ë¬ëЬ
ì€ë ëëŒëЬë íë¡ìžì€ ëŽ ë©ëªšëŠ¬ë¥Œ ìŒë¶ ê³µì íêž° ë묞ì ë©í° íë¡ìžì€ì ë¹íŽ ìì곌 ê³µê°ìŽ ì ìœëë íšê³Œê° ììµëë€.
ê·žë¬ë ëìì ì ê·Œíê³ ì€íëë íëŠìŽ ë§ë€ë ê²ì ê³µì ììì ëë¬ìŒ 묞ì ì ê°ë¥ì±ë 컀ì§ë€ë ë»ìŽêž°ë í©ëë€.
ê·ž ëíì ìž ë¬žì ë¡ êµì°© ìí(Deadlock), êž°ì ìí(Starvation), 겜ì ìí(Race Condition) ë±ìŽ ìëë°
ìŽ êžììë 겜ì ìí(Race Condition)ì ëíŽ ììží ë€ë€ë³Žê² ìµëë€.
ð 겜ì ìí (Race Condition)
겜ì ìíë ë ìŽìì ì€ë ëê° ê³µì ë ììì ëíŽ ëìì ì ê·Œí멎ì ì€í ììì ë°ëŒ ê²°ê³Œê° ë¬ëŒì§ë 묞ì 륌 ë§í©ëë€.
ì륌 ë€ìŽ ë³Œê¹ì?
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
ìì increment() ë©ìëë ëšìí count륌 1 ìŠê°ìí€ë ìœëì ëë€.
ì¬ë¬ ì€ë ëê° ëìì ìŽ ë©ìë륌 ížì¶í멎 ìŽë»ê² ë ê¹ì?
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
ë ê°ì ì€ë ëìì ê°ê° 1000ë²ì© ìŠê°ì쌰ëë°
ê²°ê³Œê° 2000ë³Žë€ ìì ì ììµëë€.
묞ì ë count++ìŽë ëììŽ ì¬ì€ ìž ê°ì ëììŒë¡ ëëêž° ë묞ì ëë€.
- count ê°ì ìœëë€
- 1ì ëíë€
- 결곌륌 ë€ì countì ì ì¥íë€
ìŽ ìž ëì ì€ê°ì ë€ë¥ž ì€ë ëê° ëŒìŽë€ë©Ž, count ê°ì ìë±íê² ìŠê°íê±°ë 걎ëë°ê² ë©ëë€.
ì륌 ë€ìŽ, ë ì€ë ëê° ìëì ê°ì ììë¡ ì€íëë€ê³ íŽëŽ ìë€.
- ì€ë ë A: count ê°ì ìœì → (count == 0)
- ì€ë ë B: count ê°ì ìœì → (count == 0)
- ì€ë ë A: 1ì ëíŽ 1 ì ì¥
- ì€ë ë B: 1ì ëíŽ 1 ì ì¥
결곌ì ìŒë¡ ë ë² ìŠê°íì§ë§ ì€ì ê°ì 1ì ëë€.
ìŽ ë¬žì 륌 íŽê²°íë €ë©Ž, ê³µì ììì ëíŽ ì€ë ëë€ìŽ ììëë¡ ì ê·Œíëë¡ "ëêž°í" ìì ìŽ íìí©ëë€.
𧪠íŽê²° ì ëµ
겜ì ìí륌 íŽê²°íêž° ìí ëêž°í ë©ì»€ëìŠìŒë¡ ìížë°°ì ì ëíŽ ììë³Žê² ìµëë€.
ð¡ ìížë°°ì (Mutual Exclusion)
ìŒë°ì ìž íë¡ìžì€ ëŽ ìœë 구조ì ëë€.
ìœë ì€ ê³µì ììì ì ê·Œíë 구ìì ìê³ êµ¬ì(critical section)ìŽëŒê³ í©ëë€.
ð ìê³ êµ¬ììŽë? (critical section?)
ë ìŽìì íë¡ìžì€ìì ëìì ì ê·ŒíŽìë ì ëë ê³µì ììì ì ê·Œíë ìœë 구ì
(a piece of code that accesses a shared resources(data structure or device) that must not be concurrently accessed by more than one processes.)
ì¬ë¬ ì€ë ëê° ëìì ìê³ êµ¬ìì ì§ì íë€ë©Ž 겜ì ìíê° ë°ìíê² ë©ëë€.
ê·žëì ìŽë¥Œ ë°©ì§íë 묞ì 륌 ìê³ êµ¬ì 묞ì (Critical Section Problem)ìŽëŒê³ ë¶ë¥Žêž°ë í©ëë€.
ìŽë¥Œ ë§êž° ìíŽ ì€ë ëê° ìê³ êµ¬ìì ë€ìŽê°êž° ì ì
ìì ìŽ ìê³ êµ¬ììì ìì íë ëì ë€ë¥ž ì€ë ëë€ìŽ ì§ì íì§ ëª»íëë¡ lockì ì€ì íê³ ,
ìê³ êµ¬ìììì ìì ìŽ ëë멎 lockì íŽì íë ëììŽ íìí©ëë€.
ìŠ, ìŽë¯ž í ì€ë ëê° ìê³ êµ¬ììì ìì ì€ìŽëŒë©Ž ë€ë¥ž ì€ë ëë ìê³ êµ¬ìì ì§ì í멎 ì ë©ëë€.
ìŽë¥Œ ìíž ë°°ì (Mutual Exclusion)ìŽëŒê³ í©ëë€.
ë€ìì ë©í°ì€ë ë í겜ìì ìížë°°ì 륌 구ííë ëíì ìž ë ê°ì§ ëêž°í ë©ì»€ëìŠ
뮀í ì€ì ìžë§í¬ìŽì ëíŽ ìŽíŽëŽ ìë€.
â 뮀í ì€(Mutex)
"í ë²ì íëë§ ë€ìŽì¬ ì ìë€"
ê³µì ììì ëíŽ í ë²ì íëì ì€ë ëë§ ì ê·Œ ê°ë¥í ì ëµì ëë€.
í ì€ë ëê° ììì ì ê·Œí멎 í늎 ëê¹ì§ ëœ(lock)ìŽ ê±žëŠœëë€.
ìŽ ëœì í ì ìë 걎 ëœì 걎 íŽë¹ ì€ë ë ë¿ì ëë€.
ìŽ ììì ì ê·Œíê³ ì íë ëëšžì§ ì€ë ëë ëœìŽ í늎 ëê¹ì§ êž°ë€ëŠœëë€.
Javaììë ìëì ê°ìŽ synchronized í€ìë륌 ë©ìëì ë¶ì¬ increment() ë©ìë ì€í ì íë¡ ëœì 걞 ì ììµëë€.
public synchronized void increment() {
count++;
}
synchronized í€ìë륌 ìŽì©í ê²œì° ìì ìŽ ëë ì€ë ëê° ëœì ë°íí ë, ë€ììŒë¡ ëœì íëí ì€ë ëê° ìŽë€ ì€ë ëìŒì§ì ëí 볎ì¥ìŽ ìêž° ë묞ì
ìŽë€ ì€ë ëë ëœì íëíì§ ëª»íê³ , ê³ì ì ê·Œì êž°ë€ëЬë êž°ì ìíê° ë ê°ë¥ì±ìŽ ììµëë€.
(ìŒë°ì ìŒë¡ë JVMìŽ ê³µì íê² ëœì ë¶ë°°íë € í©ëë€.)
ìŽë¬í 묞ì 륌 íŽê²°íêž° ìíŽ ëª ìì ëœì ì¬ì©íêž°ë í©ëë€. ëíì ìž ìë¡ Javaì ReentrantLockìŽ ììµëë€.
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
syncronized í€ìëì ëª ìì ëœ ëªšë ë€ë¥ž ì€ë ëìì íìží ì ìë ê² ìëëŒ íëì ì€ë ë ëŽììë§ ìŒìŽëë ìŒì ëë€.
ë°ëŒì 뮀í ì€ììë ëœì íëí ì€ë ëë§ìŽ ëœì íŽì í ì ììµëë€.
ìŽì²ëŒ 뮀í ì€ìì ëœì ìì ê¶ì ê°ë ìŽ ììµëë€.
뮀í ì€ì 목ì ì í ì€ë ëê° ìŽë€ ê³µì ììì ëíŽ ë ì ì ìŒë¡ ìì ì ëë§ì¹ ëê¹ì§ 볎ížíë ê²ìŽêž° ë묞ì ëë€.
ð 뮀í ì€ìì íµì¬ì í ë²ì íëì ì€ë ëë§ ì ê·Œ ê°ë¥íëë¡ ë³Žì¥íë€ë ì ì ëë€.
â ìžë§í¬ìŽ(Semaphore)
ìžë§í¬ìŽ ìì ê³µì ììì ì¬ë¬ ì€ë ëê° ì ê·Œëë ê²ì ë§ë ë°©ë²ìŽì§ë§
뮀í ì€ì ë€ë¥Žê² ë°ëì í ë²ì íëì ì€ë ëë§ ì ê·Œí ì ìë ê²ì ìëëë€.
ìžë§í¬ìŽììë ëìì ì íŽì§ ê°ìë§íŒì ì€ë ëê° ê³µì ììì ì ê·Œí ì ììµëë€.
SemaphoreëŒë ì ìí 칎ìŽí° ë³ì(ë³Žíµ së¡ íì)륌 ìŽì©íì¬ ëìì ê³µì ììì ì ê·Œí ì ìë ì€ë ëì ì륌 ì íí©ëë€.
ì²ìì ê³µì ììì ì ê·Œí ì ìë ëì ì€ë ë ì륌 Nê°ë¡ ì í멎, ìµë Nê°ë§ ëìì ìê³ êµ¬ìì ì§ì í ì ìê³ ,
ê·žë³Žë€ ë ë§ì ì€ë ëê° ì ê·Œíë €ê³ í멎 뚌ì ë€ìŽê° ìë ì€ë ëê° ëì¬ ëê¹ì§ êž°ë€ë €ìŒ í©ëë€.
"ìë.. ëìì íëì ì€ë ëë§ ìê³ êµ¬ìì ë€ìŽê°ìŒ íë€ë©Žìì?! ìžë§í¬ìŽê° ìížë°°ì ìž ê±° ë§ìì?"
겜ì ìí륌 ë§êž° ìíŽ í ìì ì ì€ì§ íëì ì€ë ëë§ ê³µì ììì ì ê·Œí ì ìëë¡ ì ííë ê²ìŽ ìíž ë°°ì ì ëë€.
ìíž ë°°ì 륌 구ííë ëêµ¬ë¡ ì€ë ìŽíŽë³ž 뮀í ì€ì ìžë§í¬ìŽ ë±ìŽ ìëê±°ì£ .
ë§ìœ ìžë§í¬ìŽìì ëìì ê³µì ììì ì ê·Œí ì ìë ì€ë ëì ê°ì륌 "1ê°"ë¡ ì€ì íë€ë©Ž
뮀í ì€ì²ëŒ í ë²ì íëì ì€ë ëë§ ë€ìŽê°ê² ì£ ? ìŽë¬í ìžë§í¬ìŽë¥Œ Binary SemaphoreëŒê³ í©ëë€.
Binary Semaphoreë¡ êµ¬íí멎 ìíž ë°°ì 륌 구íí ì ììµëë€.
ì€ë ë°°ìŽ ìíž ë°°ì ìžìë ëêž°í ì©ëë¡ ìžë§í¬ìŽë¥Œ ì¬ì©íêž°ë í©ëë€.
ìŽ Semaphoreììë P ì°ì°ê³Œ V ì°ì°ì ìŽì©íŽ ììì ì ê·Œí©ëë€.
P()ë ìê³ êµ¬ìì ì§ì íê³ ì í ë ížì¶íê³ , V()ë ìê³ êµ¬ììì ëì¬ ë ížì¶í©ëë€.
P(s) {
while(S <= 0) {
do wait; // no operation
}
S--;
}
V(s) {
S++;
}
ð P ì°ì°
ê³µì ììì ì»êž° ìíŽ ìê³ êµ¬ìì ë€ìŽê°êž° ì entry section(ì§ì 구ê°)ìì P ì°ì°ì í©ëë€.
ìŽë ìžë§í¬ìŽ ê°ì ì ê²íì¬ ëêµ°ê° ìŽ ììì ì¬ì©íëì§ ì ì ììµëë€.
ë§ìœ ìžë§í¬ìŽ s > 0 ìŽë©Ž, íŽë¹ ì€ë ëê° ììì ì ê·Œí ì ìë€ë ì믞ì ëë€.
s륌 1 ê°ììí€ê³ ìê³ êµ¬ìì ì§ì í©ëë€.
ë°ë©Ž s <= 0ìŽë©Ž ë€ë¥ž ì€ë ëê° ìŽë¯ž ìê³ êµ¬ììì ìì ì€ìŽëŒë ì믞ìŽë¯ë¡ sê° ë€ì ììê° ë ëê¹ì§ ëêž°í©ëë€.
ìŽë së 묎ìì ì믞í ê¹ì? ë°ë¡ "íì¬ ìê³ êµ¬ìì ì§ì ê°ë¥í ì€ë ëì ì"ì ëë€.
ð V ì°ì°
Vì°ì°ì ì ì íê³ ìë ê³µì ììì íìŽì£Œë ê²ì ëë€.
ìê³ êµ¬ììì ë²ìŽë exit sectionì ì ìŽë€ ë V ì°ì°ì ìíí©ëë€.
ì€ë ëê° ê³µì ììì ëí ìì ì ëëŽë©Ž ìžë§í¬ìŽ sì ê°ìŽ 1 ìŠê°í©ëë€.
ìŽë ëêž°íê³ ìë(sleep ìíìŽë) ì€ë ëê° ììë€ë©Ž ì ìì 깚ìŽë ê³µì ììì ì ê·Œíê² ë©ëë€.
ìžë§í¬ìŽë 뮀í ì€ì ë¬ëЬ ëœì ëí ìì ê¶ ê°ë ìŽ ìë ê³µì ìì ì ê·Œ ì ìŽ ë구ì ëë€.
ìžë§í¬ìŽë¥Œ ì¬ì©íë ìŽë€ ì€ë ëëŒë V ì°ì°ìŒë¡ ìžë§í¬ìŽ ê°ì ìŠê°ììŒ ììì íŽì í ì ììµëë€.
V ì°ì°ì “ê³µì ììì ì¬ì©ìŽ ëë¬ìì ì늎 ì±
ììŽ ìë ì€ë ë”ê° ížì¶í©ëë€.
ìŽ ì€ë ëë ë°ëì P ì°ì°ì íë ê°ì ì€ë ëìŒ íìë ììµëë€. (ë¬Œë¡ ê°ìë ë©ëë€.)
ì륌 ë€ìŽ ìŽë° 겜ì°ê° ìë€ê³ í©ìë€. (ì°žê³ ë¡ ìŽ ììë ìŽì첎ì ìì ë§ìŽ ììë¡ ëë ìì°ì - ìë¹ì 묞ì 륌 ëšìíí ë²ì ì ëë€.)
- ð§ðŸ ìì°ì Producer: ìíì ìì°íŽ ë§ížì ë©ííš
- 𧺠ìë¹ì Consumer: ë§ížìì ìíì 구ì íš
- 묞ì : ìë¹ìë ë§ížì ìíìŽ ììŒë©Ž êž°ë€ë €ìŒ íš
- â¡ïž ìì°ìê° ë§ížì ë©ííì ë ìë¹ììê² "ìŽì ì¬!"íê³ ì ížë¥Œ ì€ìŒ íš
ìŽë ìžë§í¬ìŽë íì¬ ë§ížì ìí ì¬ê³ ê° ëª ê° ìëì§ë¥Œ ëíëŽë ì«ì 칎ìŽí°ì ëë€.
Semaphore items = new Semaphore(0); // íì¬ ë§ížì ìíìŽ 0ê° ìë€ê³ ê°ì
Thread producer = new Thread(() -> {
while (true) {
produceItem();
items.release(); // V ì°ì°! ìí íë ì¶ê°íìŽ!
}
});
Thread consumer = new Thread(() -> {
while (true) {
items.acquire(); // P ì°ì°! ì¬ê³ ê° ììŒë©Ž êž°ë€ëŠŒ
consumeItem(); // ìí 구ì
}
});
Producerë V ì°ì°ë§, Consumerë P ì°ì°ë§ í©ëë€.
ìŽë¡ìš ìì°ìë ìë¹ììê² ë¬Œê±Žì ì¶ê°íë€ê³ ìëŠ¬ê³ , ìë¹ìë ìì°ììê² ë¬Œê±ŽìŽ íìíë€ê³ ì늎 ì ìì£ .
ìžë§í¬ìŽë "ëê°" ììì ì ê·Œíëì§ê° ì€ìí ê² ìëëŒ
"ëª ê°ì ì€ë ë"ê° ììì ì ê·Œíëì§ê° ì€ìíêž° ë묞ì ë구ë ëœì íŽì í ì ììµëë€.
ì 늬íì멎,
뮀í ì€ììë íëì ììì ëìì íëì ì€ë ëë§ìŽ ì ê·Œí ì ììê³ , ëœì ì€ì í ì€ë ëë§ ëœì íŽì í ì ììµëë€.
(ëêž°í ëììŽ íë)
ìžë§í¬ìŽììë 믞늬 ì§ì í ìµë Nê°ì ì€ë ëê° íëì ììì ëì ì ê·Œí ì ììµëë€. ë구ë ëœì íŽì í ì ììµëë€.
(ëêž°í ëììŽ íë ìŽì)
ð¡ ììœ
ë©í°ì€ë ë í겜ììë
ì¬ë¬ ì€ë ëê° ê³µì ììì ëìì ì ê·Œí멎ì
ë°ìŽí° ë¶ìŒì¹ë ìêž°ì¹ ìì ëì 묞ì ê° ìŒìŽë ì ììµëë€.
ìŽë¥Œ ë°©ì§íë €ë©Ž ëìì ì€íëë ì€ë ë ê° ìì ì ê·Œì ì¡°ìšíŽìŒ íë©°,
ìŽë¥Œ ìíŽ ë®€í
ì€(Mutex), ìžë§í¬ìŽ(Semaphore)ì ê°ì ëêž°í ë구륌 ì¬ì©í©ëë€.
- ð§µ ë©í°ì€ë ë í겜(Multi-Thread): ëìì ì¬ë¬ ìì ìŽ ê°ë¥íì§ë§, ê³µì ìì ì¶©ë ìíìŽ ìì
- â ïž ê²œì ìí(Race Condition): ì¬ë¬ ì€ë ëê° ëìì ê°ì ììì ì ê·Œí ë ì€í ììì ë°ëŒ ì€ë¥ ë°ì
- â ìíž ë°°ì (Mutual Exclusion): ìŽë¯ž ìê³ êµ¬ì(critical section)ìì ìì ì€ìž ì€ë ëê° ìë€ë©Ž, ë€ë¥ž ì€ë ëë ì ê·Œ ë¶ê°
- ð 뮀í ì€ (Mutex): í ë²ì íëë§ ì ê·Œ ê°ë¥, ëœ ìì ìë§ íŽì ê°ë¥
- ð¢ ìžë§í¬ìŽ (Semaphore): ëìì ì¬ë¬ ì€ë ë ì ê·Œ ê°ë¥, ìì ì êŽê³ ììŽ íŽì ê°ë¥
ì°žê³ ìë£
- ë©í° íë¡ìžì€ vs ë©í° ì€ë ë ë¹êµ ìì ìŽì 늬
- ì€ë ë(Thread), ë©í°ì€ë ë(Multi-Thread)!
- 겜ì ìí(Race Condition)
- [Thread] 뮀í ì€, ìžë§í¬ìŽ, 몚ëí°ì ì€ë ë ëêž°íì 구í ìì
- êŽìŽëíêµ ìì€í íë¡ê·žëë° êµê³Œëª© ê°ììë£
- + íì íìì ëì êž
'âïž CS & êž°í ê°ë° ìë£' 칎í ê³ ëŠ¬ì ë€ë¥ž êž
ë¡ì»¬ ìºì & ë¶ì° ìºì ìŽíŽíêž° (1) | 2025.06.12 |
---|---|
ìºì(Cache) ê°ë ìœê² ì 늬íêž° (1) | 2025.06.03 |
âïž íë¡ìžì€(Process) / ì€ë ë(Thread) ê°ë ì 늬 (3) | 2025.06.02 |
ëë²ê¹ ì ì€ìì± (0) | 2025.05.14 |
[ê¹íëž] Codecov ì ì©íì¬ PRì í ì€íž 컀ë²ëЬ ë±ì§ ë¬êž° (1) | 2025.04.25 |