ํฌ์ŠคํŠธ

CS โ€” context switching

CS โ€” context switching

๐Ÿ“• 05/12 โ€” Context Switching์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”

๋ชจ์˜๋ฉด์ ‘ ์ฃผ์ œ: โ€œContext Switching์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”โ€ ์ •์˜ยท๋ฐœ์ƒ ์‹œ์  โ†’ PCB/TCB ์ €์žฅยท๋ณต์› โ†’ ๋ชจ๋“œ ์Šค์œ„์น˜ โ‰  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ โ†’ ๋น„์šฉ ์š”์†Œ(์บ์‹œ flushยทTLB flushยทํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€) โ†’ ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ ๋น„์šฉ ์ฐจ โ†’ ์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ์˜ ์—ฐ๊ด€ โ†’ Windows ๊นŠ์ด(Win32 ์Šค๋ ˆ๋“œ APIยท๋™๊ธฐํ™” ๊ฐ์ฒดยทConcRT/PPLยทFiberยทUMSยทC++ ํ‘œ์ค€ ๋งคํ•‘ยทTLSยทCRT ์˜ต์…˜) โ†’ ์–ธ๋ฆฌ์–ผ(FRunnableThreadยทTaskGraphยทGameThread/RenderThread/RHIThread)๊นŒ์ง€


ํ•™์Šต ์˜์—ญ โ€” 19ยท20๋ฒˆ์—์„œ ํŒŒ์ƒ๋œ OSยท๋™์‹œ์„ฑ ํšŒ๊ท€

19๋ฒˆ์—์„œ ํ”„๋กœ์„ธ์Šค/์Šค๋ ˆ๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด์„œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ํ•ต์‹ฌ ์ฐจ์ด ์…‹ ์ค‘ ํ•˜๋‚˜๋กœ ๋‹ค๋ค˜๊ณ , 20๋ฒˆ์—์„œ ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์™€ ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ ์Šคํƒ์„ ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. 21๋ฒˆ์€ ๊ทธ ์‚ฌ์ด ๋‹ค๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” โ€œ์Šค๋ ˆ๋“œ ์ „ํ™˜ ์ž์ฒด๊ฐ€ ์–ด๋–ป๊ฒŒ ์ผ์–ด๋‚˜๊ณ  ์™œ ๋น„์‹ผ๊ฐ€โ€œ๋ฅผ ๋ณธ ์ฃผ์ œ๋กœ ๋Œ์–ด์˜ฌ๋ฆฝ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
01๋ฒˆ ๋ฉ”๋ชจ๋ฆฌ 4์˜์—ญ (Code/Data/Heap/Stack)        โ† ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”ยท๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ํ† ๋Œ€
03๋ฒˆ new vs malloc (ํž™ vs ์Šคํƒ)                  โ† ์บ์‹œ ๋™์ž‘ ์ดํ•ด ํ† ๋Œ€
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
19๋ฒˆ ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ                          โ† PCB/TCBยท์ปจํ…์ŠคํŠธ ๋น„์šฉ 5~10๋ฐฐ ์ฐจ์ด ์ฒซ ๋“ฑ์žฅ
20๋ฒˆ Stack Overflow (์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ ์Šคํƒ)         โ† SPยท๊ฐ€๋“œ ํŽ˜์ด์ง€ยท์Šคํƒ ํ•œ๊ณ„
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
21๋ฒˆ Context Switching (โ˜…)                       โ† ๋ณธ ์ฃผ์ œ ํ™•์žฅ
์ดํ›„ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌยทํŽ˜์ด์ง• / ์Šค์ผ€์ค„๋Ÿฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ / ์บ์‹œ ์ผ๊ด€์„ฑ (MESI)

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ OS ์Šค์ผ€์ค„๋Ÿฌ + CPU ๋งˆ์ดํฌ๋กœ์•„ํ‚คํ…์ฒ˜ + ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ + ์บ์‹œ ๊ณ„์ธต์ด ๋ชจ๋‘ ๋งŒ๋‚˜๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ์ฃผ์ œ ์•ˆ์— OSยทํ•˜๋“œ์›จ์–ดยท์ปดํŒŒ์ผ๋Ÿฌยท์–ธ์–ด ํ‘œ์ค€ยทํ”Œ๋žซํผ API๊ฐ€ ๋™์‹œ์— ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค. Windows๋Š” ํŠนํžˆ CreateThreadยทCritical SectionยทSRWLockยทFiberยทUMS ๊ฐ™์€ ํ’๋ถ€ํ•œ API ๊ณ„์ธต์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ, MSVC ๋ฌธ์„œ๋ฅผ ๋”ฐ๋ผ ๋‚ด๋ ค๊ฐ€๋ฉด โ€œ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ โ†’ ์ปค๋„ ๋ชจ๋“œ ๊ฐ•์ œโ€ ๊นŒ์ง€์˜ ๋น„์šฉ ์ŠคํŽ™ํŠธ๋Ÿผ์„ ๋‹จ๊ณ„๋ณ„๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ CPU ์ฝ”์–ด ์œ„์—์„œ ์‹คํ–‰๋˜๋˜ ํ•œ ์‹คํ–‰ ๋‹จ์œ„(์Šค๋ ˆ๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค)๋ฅผ ์ž ์‹œ ๋‚ด๋ ค๋†“๊ณ , ๋‹ค๋ฅธ ์‹คํ–‰ ๋‹จ์œ„๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ํ•ต์‹ฌ์€ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ด๋˜ ๋‹จ์œ„์˜ ์ƒํƒœ(๋ ˆ์ง€์Šคํ„ฐยทSPยทPC ๋“ฑ)๋ฅผ ์žƒ์ง€ ์•Š๋„๋ก ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๊ณ , ์ƒˆ๋กœ ๋“ค์–ด์˜ฌ ๋‹จ์œ„์˜ ์‹คํ–‰ ์ƒํƒœ๊ฐ€ ๋ฉˆ์ท„๋˜ ์‹œ์  ๊ทธ๋Œ€๋กœ ๋ณต์›๋˜๋„๋ก ์ €์žฅ๋œ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ CPU ๋ ˆ์ง€์Šคํ„ฐ๋กœ ์ ์žฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ƒํƒœ๋ฅผ โ€œ์ปจํ…์ŠคํŠธ(context)โ€๋ผ ๋ถ€๋ฅด๊ณ , ๊ทธ๋ž˜์„œ ์ด ์ž‘์—…์˜ ์ด๋ฆ„์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ(context switching)์ž…๋‹ˆ๋‹ค. OS๋Š” ์ด ์ •๋ณด๋ฅผ PCB(Process Control Block, ํ”„๋กœ์„ธ์Šค ์ œ์–ด ๋ธ”๋ก)์™€ TCB(Thread Control Block, ์Šค๋ ˆ๋“œ ์ œ์–ด ๋ธ”๋ก)๋ผ๋Š” ์ปค๋„ ์ž๋ฃŒ๊ตฌ์กฐ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ๋Š” ํฌ๊ฒŒ ๋„ค ๊ฐ€์ง€๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. ํ•œ ๋‹จ๋ฝ์— ์ฃฝ ๋Š˜์–ด๋†“๊ธฐ๋ณด๋‹ค ๊ธ€๋จธ๋ฆฌํ‘œ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒŒ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค.

  • ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ(timer interrupt) ๋งŒ๋ฃŒ โ€” OS ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋งค ์Šค๋ ˆ๋“œ์— ํ• ๋‹นํ•ด ๋‘” ์‹œ๊ฐ„ ์กฐ๊ฐ(time slice, ๋ณดํ†ต ์ˆ˜ ms)์ด ๋๋‚˜๋ฉด ๊ฐ•์ œ๋กœ ์Šค์œ„์นญํ•ฉ๋‹ˆ๋‹ค. ์„ ์ ํ˜• ์Šค์ผ€์ค„๋ง์˜ ๋ณธ์ฒด์ž…๋‹ˆ๋‹ค.
  • ๋ธ”๋กœํ‚น I/O ๋˜๋Š” ์‹œ์Šคํ…œ ์ฝœ โ€” read()ยทrecv()ยทWaitForSingleObject()์ฒ˜๋Ÿผ ๋Œ€๊ธฐ๋ฅผ ๋™๋ฐ˜ํ•˜๋Š” ํ˜ธ์ถœ์„ ๋งŒ๋‚˜๋ฉด ๊ทธ ์Šค๋ ˆ๋“œ๋Š” ์ฆ‰์‹œ Wait ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๊ณ , ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค๋ฅธ Ready ์Šค๋ ˆ๋“œ๋ฅผ ๊ณจ๋ผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ โ€” mutexยทsemaphoreยทevent๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ condition variable์—์„œ ์ž ๋“ค๋ฉด ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊นฌ ๋’ค ๋‹ค์‹œ Ready ํ์— ๋“ค์–ด๊ฐ”๋‹ค๊ฐ€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์œผ๋กœ ๋ณต๊ท€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ž๋ฐœ์  ์–‘๋ณด(voluntary yield) โ€” Sleep(0)ยทSwitchToThreadยทstd::this_thread::yield์ฒ˜๋Ÿผ ์Šค๋ ˆ๋“œ๊ฐ€ ์ง์ ‘ CPU๋ฅผ ๋‚ด๋ ค๋†“๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์ด๋•Œ๋„ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค์Œ ํ›„๋ณด๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ์Šค์œ„์นญํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ž์ฃผ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ฒŒ ๋ชจ๋“œ ์Šค์œ„์น˜(mode switch)์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜(context switch)์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. ๋ชจ๋“œ ์Šค์œ„์น˜๋Š” ๊ฐ™์€ ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ(user mode)์™€ ์ปค๋„ ๋ชจ๋“œ(kernel mode)๋ฅผ ์˜ค๊ฐ€๋Š” ๊ฒƒ์œผ๋กœ, ์‹œ์Šคํ…œ ์ฝœ ํ˜ธ์ถœ์ด๋‚˜ ํ•˜๋“œ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ ์‹œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ์ผ๋ถ€ ์ €์žฅยท๋ณต์›ํ•˜๊ธด ํ•˜์ง€๋งŒ ์‹คํ–‰ ์ฃผ์ฒด(์Šค๋ ˆ๋“œ)๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฏ€๋กœ PCBยทTCB ๊ต์ฒด๊ฐ€ ์—†๊ณ , ๋น„์šฉ๋„ ํ›จ์”ฌ ์ž‘์Šต๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ ์ผ์–ด๋‚˜์ง€๋งŒ, ๋ชจ๋“œ ์Šค์œ„์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ญ์ƒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค โ€” ์‹œ์Šคํ…œ ์ฝœ์ด ์ฆ‰์‹œ ๋๋‚˜๋ฉด ๊ฐ™์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋Œ์•„์˜ฌ ๋ฟ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ๊ฐˆ์•„๋ผ์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋น„์šฉ์€ ์—ฌ๋Ÿฌ ์ธต์—์„œ ๋ˆ„์ ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ๋„ ๊ธ€๋จธ๋ฆฌํ‘œ๋กœ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์› โ€” ๋ฒ”์šฉ ๋ ˆ์ง€์Šคํ„ฐ(general purpose register), SP(Stack Pointer, ์Šคํƒ ํฌ์ธํ„ฐ), PC(Program Counter, ํ”„๋กœ๊ทธ๋žจ ์นด์šดํ„ฐ), ํ”Œ๋ž˜๊ทธ ๋ ˆ์ง€์Šคํ„ฐ, FPUยทSIMD ๋ ˆ์ง€์Šคํ„ฐ(x86_64์—์„œ XMMยทYMMยทZMM)๋ฅผ PCB/TCB๋กœ ์˜ฎ๊ธฐ๋Š” ์ง์ ‘ ๋น„์šฉ. ๋ณดํ†ต ์ˆ˜๋ฐฑ nanosecond.
  • ์บ์‹œ ์ฝœ๋“œ(cache cold) โ€” ์ƒˆ ์Šค๋ ˆ๋“œ์˜ ๋ฐ์ดํ„ฐยท๋ช…๋ น์–ด๊ฐ€ L1ยทL2 ์บ์‹œ์— ์—†์–ด ์ง„์ž… ์งํ›„ ์ค„์ค„์ด ์บ์‹œ ๋ฏธ์Šค(cache miss)๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ์ง์ ‘ ๋น„์šฉ๋ณด๋‹ค ํ›จ์”ฌ ํฐ ๊ฐ„์ ‘ ๋น„์šฉ์ž…๋‹ˆ๋‹ค.
  • TLB(Translation Lookaside Buffer, ์ฃผ์†Œ ๋ณ€ํ™˜ ์บ์‹œ) flush โ€” ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์—์„œ๋งŒ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์ด ๋ฐ”๋€Œ๋ฏ€๋กœ MMU(Memory Management Unit, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์œ ๋‹›)๊ฐ€ ์บ์‹ฑํ•ด๋‘๋˜ ๊ฐ€์ƒโ†’๋ฌผ๋ฆฌ ๋งคํ•‘์„ ๋น„์›Œ์•ผ ํ•˜๊ณ , ์ดํ›„ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ๋งˆ๋‹ค ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ(page table walk)๊ฐ€ ๋‹ค์‹œ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด ์Šค๋ ˆ๋“œ ์ „ํ™˜์—์„  ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€(pipeline stall)์™€ ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ(branch predictor) ๋ฌดํšจํ™” โ€” CPU์˜ instruction pipeline์— ๋“ค์–ด ์žˆ๋˜ ๋ช…๋ น๋“ค์ด ๋ชจ๋‘ ํ๊ธฐ๋˜๊ณ , ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ๊ฐ€ ํ•™์Šตํ•ด ๋‘” ํŒจํ„ด๋„ ์ƒˆ ์Šค๋ ˆ๋“œ ์ฝ”๋“œ์™€ ์–ด๊ธ‹๋‚˜ ์ž ์‹œ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.
  • ์ปค๋„ ์ง„์ž… ๋น„์šฉ โ€” ์‹œ์Šคํ…œ ์ฝœ๋กœ ์ง„์ž…ํ•ด ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‹ค์‹œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋Œ์•„์˜ค๋Š” ๋ฐ ๋“œ๋Š” ๋ชจ๋“œ ์Šค์œ„์น˜ ์ž์ฒด ๋น„์šฉ.

ํ”„๋กœ์„ธ์Šค ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜์™€ ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜์˜ ๋น„์šฉ ์ฐจ์ด๋Š” ์ด ๋น„์šฉ ํ•ญ๋ชฉ ์ค‘ ์–ด๋А ๊ฒƒ์ด ๋ฐœ์ƒํ•˜๋А๋ƒ๋กœ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ์ „ํ™˜์€ ๊ฐ™์€ PCB(๊ฐ™์€ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„) ์•ˆ์—์„œ TCB๋งŒ ๋ฐ”๊พธ๋ฏ€๋กœ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค ๋ ˆ์ง€์Šคํ„ฐ(x86 CR3)๋ฅผ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  TLBยทํ•ธ๋“ค ํ…Œ์ด๋ธ”๋„ ๋ณด์กด๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์€ CR3๋ฅผ ๊ต์ฒดํ•˜๊ณ  TLB๋ฅผ ๋น„์›Œ์•ผ ํ•˜๋‹ˆ, ์งํ›„ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ๋ชจ๋‘ TLB miss๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ์Šค๋ ˆ๋“œ ์ „ํ™˜์ด ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋ณด๋‹ค 5~10๋ฐฐ ๋น ๋ฅด๋‹ค๋Š” ๋ง์ด ๋‚˜์˜ต๋‹ˆ๋‹ค โ€” 19๋ฒˆ์—์„œ ์ •๋ฆฌํ•œ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ตœ๊ทผ CPU๋Š” ASID(Address Space ID) ๋˜๋Š” PCID(Process Context ID, x86)๋กœ TLB ์—”ํŠธ๋ฆฌ๋ฅผ ํ”„๋กœ์„ธ์Šค๋ณ„๋กœ ํƒœ๊น…ํ•ด์„œ ์ „ํ™˜ ์‹œ ์ „์ฒด flush๋ฅผ ํšŒํ”ผํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ์บ์‹œ ์ฝœ๋“œ๋Š” ํ”ผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์˜ ๋นˆ๋„์™€ ์ •์ฑ…์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์„ ์ ํ˜•(preemptive) ์Šค์ผ€์ค„๋ง์€ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ๊ฐ•์ œ ์Šค์œ„์นญ์„ ์ผ์œผํ‚ค๋Š” ๋ชจ๋ธ๋กœ WindowsยทLinux์˜ ํ‘œ์ค€์ด๊ณ , ๋น„์„ ์ ํ˜•(non-preemptive)ยทํ˜‘๋ ฅ์ (cooperative) ์Šค์ผ€์ค„๋ง์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž๋ฐœ์ ์œผ๋กœ ์–‘๋ณดํ•  ๋•Œ๋งŒ ์Šค์œ„์นญํ•˜๋Š” ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. ๋ผ์šด๋“œ ๋กœ๋นˆ(Round-Robin)์€ ๋ชจ๋“  Ready ์Šค๋ ˆ๋“œ์— ๊ฐ™์€ time slice๋ฅผ ๋Œ๋ฆฌ๋Š” ๋ฐฉ์‹, ์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง(priority scheduling)์€ ์šฐ์„ ์ˆœ์œ„ ์ˆœ์„œ๋Œ€๋กœ ๋””์ŠคํŒจ์น˜ํ•˜๋Š” ๋ฐฉ์‹, MLFQ(Multi-Level Feedback Queue)๋Š” ๊ทธ ๋‘˜์„ ๊ฒฐํ•ฉํ•ด ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์ž‘์—…๊ณผ ๋ฐฐ์น˜ ์ž‘์—…์„ ์ž๋™ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. time slice๋ฅผ ์งง๊ฒŒ ์žก์œผ๋ฉด ์‘๋‹ต์„ฑ์ด ์ข‹์•„์ง€์ง€๋งŒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์ด ๋ˆ„์ ๋˜๊ณ , ๊ธธ๊ฒŒ ์žก์œผ๋ฉด throughput์ด ์ข‹์•„์ง€์ง€๋งŒ ์‘๋‹ต์„ฑ์ด ๋–จ์–ด์ง€๋Š” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Windows๋Š” ๋ณดํ†ต ์•ฝ 15.6ms๋ฅผ ๊ธฐ๋ณธ quantum์œผ๋กœ ์“ฐ๊ณ , ๋ฉ€ํ‹ฐ๋ฏธ๋””์–ด ํƒ€์ด๋จธ API๋กœ 1ms๊นŒ์ง€ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Windows ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋น„์šฉ์„ ์ค„์ด๋Š” ๋‹จ๊ณ„๊ฐ€ ์—ฌ๋Ÿฌ ์ธต์ž…๋‹ˆ๋‹ค. Win32 ์Šค๋ ˆ๋“œ API(CreateThread, WaitForSingleObject)๋Š” ํ•ญ์ƒ ์ปค๋„ ๋ชจ๋“œ๋ฅผ ๊ฑฐ์น˜๊ณ , Critical Section์€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ยท๊ฒฝํ•ฉ ์‹œ์—๋งŒ ์ปค๋„ ์ง„์ž…(SRWLock๋„ ๋น„์Šท), Concurrency Runtime/PPL์€ ๊ทธ ์œ„์— ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  Task Scheduler๋ฅผ ๋‘์–ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ๋” ํšŒํ”ผ, Fiber API(CreateFiber/SwitchToFiber)๋Š” ์•„์˜ˆ ์ปค๋„ ๊ฐœ์ž… ์—†๋Š” ํ˜‘๋ ฅ์  ์Šค์œ„์นญ, UMS(User-Mode Scheduling)๋Š” ๊ทธ ๋‘˜์˜ ์ ˆ์ถฉ ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. C++ ํ‘œ์ค€์˜ std::threadยทstd::mutex๋Š” Windows์—์„  ๊ฒฐ๊ตญ ์ด ์œ„์— ๋งคํ•‘๋˜๊ณ , MSVC ๋Ÿฐํƒ€์ž„์ด SRWLock ๊ฐ™์€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„  ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์„ ํƒํ•ด ๋น„์šฉ์„ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ โ€œ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋น„์‹ธ๋‹คโ€๋Š” ์ผ๋ฐ˜๋ก ์€ ๋งž์ง€๋งŒ, ์–ด๋–ค ๋™๊ธฐํ™” ๋„๊ตฌ๋ฅผ ๊ณ ๋ฅด๋А๋ƒ์— ๋”ฐ๋ผ ๊ฐ™์€ ์ž‘์—…์ด 100๋ฐฐ๊นŒ์ง€ ๋นจ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ธ๋ฆฌ์–ผ ์—”์ง„๋„ ์ด ์›๋ฆฌ๋ฅผ ๋”ฐ๋ผ GameThreadยทRenderThreadยทRHIThread๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  ๊ทธ ์‚ฌ์ด๋ฅผ ๋ช…๋ น ํ(command queue)๋กœ ์—ฐ๊ฒฐํ•ด ๋™๊ธฐํ™” ๋นˆ๋„๋ฅผ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ํ”ผํ•  ์ˆ˜ ์—†๋Š” OS ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๊ณ , ์—”์ง€๋‹ˆ์–ด๋ง์€ ๊ทธ ๋นˆ๋„์™€ ๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐ€๋Š” ๊ฒŒ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.


ํ•ต์‹ฌ ๊ฐœ๋…

๋ถ„๋ฅ˜ํ‚ค์›Œ๋“œํ•œ ์ค„ ์ •์˜
์ •์˜์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ (Context Switching)CPU ์ฝ”์–ด์—์„œ ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” OS ์ž‘์—…
ย ์ปจํ…์ŠคํŠธ (Context)์Šค๋ ˆ๋“œ ์‹คํ–‰์„ ์žฌ๊ฐœํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ์ƒํƒœ (๋ ˆ์ง€์Šคํ„ฐยทSPยทPCยทํ”Œ๋ž˜๊ทธยทFPU ๋“ฑ)
ย ๋ชจ๋“œ ์Šค์œ„์น˜ (Mode Switch)๊ฐ™์€ ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ user mode โ†” kernel mode ์ „ํ™˜. PCB ๊ต์ฒด ์—†์Œ
ย ์ธํ„ฐ๋ŸฝํŠธ (Interrupt)์™ธ๋ถ€ ์žฅ์น˜ยทCPU ์˜ˆ์™ธยทsyscall ๋ช…๋ น์ด ํ˜„์žฌ ์‹คํ–‰ ํ๋ฆ„์„ ์ค‘๋‹จ์‹œํ‚ค๊ณ  IDT์— ๋“ฑ๋ก๋œ ํ•ธ๋“ค๋Ÿฌ๋กœ ๊ฐ•์ œ ์ ํ”„์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜. ๋ชจ๋“œ ์Šค์œ„์น˜์˜ ์ฃผ๋œ ํŠธ๋ฆฌ๊ฑฐ
์ž๋ฃŒ๊ตฌ์กฐPCB (Process Control Block, ํ”„๋กœ์„ธ์Šค ์ œ์–ด ๋ธ”๋ก)OS๊ฐ€ ํ”„๋กœ์„ธ์Šค ์ •๋ณด ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์ฒด (PIDยทํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”ยทํ•ธ๋“คยท๋ฉ”๋ชจ๋ฆฌ๋งต)
ย PCB์˜ ์—ญํ• โ‘  ํ”„๋กœ์„ธ์Šค ์‹๋ณ„(PID) โ‘ก ์ฃผ์†Œ ๊ณต๊ฐ„ ๊ฒฉ๋ฆฌ(ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค ๋ณด๊ด€) โ‘ข ์ž์› ๊ด€๋ฆฌ(์—ด๋ฆฐ ํŒŒ์ผยทํ•ธ๋“คยท์‹œ๊ทธ๋„) โ‘ฃ ์Šค์ผ€์ค„๋ง ์ƒํƒœ ์ถ”์ (Ready/Running/Wait) โ‘ค ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์‹œ ์ €์žฅ ๋งค์ฒด. Windows์—์„  EPROCESS, Linux์—์„  task_struct
ย TCB (Thread Control Block, ์Šค๋ ˆ๋“œ ์ œ์–ด ๋ธ”๋ก)์Šค๋ ˆ๋“œ ์ •๋ณด (TIDยท๋ ˆ์ง€์Šคํ„ฐ ์ปจํ…์ŠคํŠธยทSPยทPCยท์šฐ์„ ์ˆœ์œ„ยท์ƒํƒœ)
๋ฐœ์ƒ ์‹œ์ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธquantum(time slice) ๋งŒ๋ฃŒ ์‹œ OS๊ฐ€ ๊ฐ•์ œ ์Šค์œ„์นญ
ย ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœreadยทrecvยทWaitForSingleObject โ€” ๋Œ€๊ธฐ ๋™๋ฐ˜ ํ˜ธ์ถœ
ย ๋™๊ธฐํ™” ๋Œ€๊ธฐmutexยทsemaphoreยทeventยทcondition variable์—์„œ ๋ธ”๋ก
ย ์ž๋ฐœ์  ์–‘๋ณด (yield)Sleep(0)ยทSwitchToThreadยทstd::this_thread::yield
๋ ˆ์ง€์Šคํ„ฐ๋ ˆ์ง€์Šคํ„ฐ (Register)CPU ์ฝ”์–ด ๋‚ด๋ถ€์˜ ์ดˆ๊ณ ์† ์ €์žฅ ๊ณต๊ฐ„(64bit ร— ์ˆ˜์‹ญ ๊ฐœ). ๋ชจ๋“  ์—ฐ์‚ฐ์ด ๊ทธ ์œ„์—์„œ ์ผ์–ด๋‚˜๊ณ , ์Šค๋ ˆ๋“œ ์‹คํ–‰ ์ƒํƒœ(PCยทSPยท์ค‘๊ฐ„๊ฐ’)๊ฐ€ ์—ฌ๊ธฐ ๋‹ด๊ฒจ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์˜ ๋ฐฑ์—… ๋Œ€์ƒ์ด ๋œ๋‹ค
ย ๋ ˆ์ง€์Šคํ„ฐ vs ๋ฉ”๋ชจ๋ฆฌ๋‘˜ ๋‹ค โ€œ๋ฐ์ดํ„ฐ ์ €์žฅ ๊ณต๊ฐ„โ€์ด์ง€๋งŒ ์œ„์น˜ยท์†๋„๊ฐ€ ๋‹ค๋ฆ„. ๋ ˆ์ง€์Šคํ„ฐ๋Š” CPU ์ฝ”์–ด ๋‚ด๋ถ€ (0.3ns), RAM์€ CPU ๋ฐ– ๋ฉ”๋ชจ๋ฆฌ ์Šฌ๋กฏ (~100ns). ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต์˜ ์ตœ์ƒ์œ„ ๋‹จ์œผ๋กœ ๋ณดํ†ต โ€œ๋ฉ”๋ชจ๋ฆฌโ€๋ผ ๋ถ€๋ฅด์ง€ ์•Š์Œ โ€” ์šด์˜์ฒด์ œ ๊ต๊ณผ์„œ์—์„œ๋„ โ€œ๋ ˆ์ง€์Šคํ„ฐ โ‰  ๋ฉ”๋ชจ๋ฆฌโ€๋กœ ๊ตฌ๋ถ„
ย PC (Program Counter)๋‹ค์Œ ์‹คํ–‰ํ•  ๋ช…๋ น์–ด ์ฃผ์†Œ. ๋ณต์›์˜ ํ•ต์‹ฌ
ย SP (Stack Pointer)์Šค๋ ˆ๋“œ ์ž๊ธฐ ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ. TCB์— ์ €์žฅ
ย ๋ฒ”์šฉ ๋ ˆ์ง€์Šคํ„ฐ (GPR)x86_64: raxยทrbxยทrcxยทrdxยทrsiยทrdiยทr8~r15
ย FPU/SIMD ๋ ˆ์ง€์Šคํ„ฐXMM/YMM/ZMM. ์‚ฌ์šฉ ์‹œ lazy save๋กœ ๋น„์šฉ ์ ˆ๊ฐ
ย CR3 (ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค)๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ์‹๋ณ„. ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ์‹œ ๊ต์ฒด
๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต (Memory Hierarchy)CPU โ† ๋ ˆ์ง€์Šคํ„ฐ(0.3ns) โ† L1(~1nsยท32~64KB) โ† L2(~3nsยท์ˆ˜๋ฐฑKB) โ† L3(~10nsยท์ˆ˜MB) โ† RAM(~100nsยทGB) โ† SSD(~100ฮผs). ์œ„๋กœ ๊ฐˆ์ˆ˜๋ก ๋น ๋ฅด๊ณ  ์ž‘์Œ
ย L1/L2/L3 ์บ์‹œRAM๊ณผ ๋ ˆ์ง€์Šคํ„ฐ ์‚ฌ์ด์˜ SRAM ์บ์‹œ. L1ยทL2๋Š” ์ฝ”์–ด ์ „์šฉ, L3๋Š” ์ฝ”์–ด ๊ณต์œ . ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์งํ›„ ์ƒˆ ์Šค๋ ˆ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ์— ์—†์œผ๋ฉด โ€œ์บ์‹œ ์ฝœ๋“œโ€ ๋ฐœ์ƒ
ย SRAM vs DRAM๋ ˆ์ง€์Šคํ„ฐยท์บ์‹œ๋Š” SRAM(ํŠธ๋žœ์ง€์Šคํ„ฐ 6๊ฐœ๋กœ 1bit, ๋น ๋ฅด์ง€๋งŒ ๋น„์‹ธ๊ณ  ํผ). RAM์€ DRAM(ํŠธ๋žœ์ง€์Šคํ„ฐ+์ปคํŒจ์‹œํ„ฐ 1์Œ, ๋А๋ฆฌ์ง€๋งŒ ์‹ธ๊ณ  ์ž‘์Œ โ†’ ๋Œ€์šฉ๋Ÿ‰ ๊ฐ€๋Šฅ)
๋น„์šฉ ์š”์†Œ์บ์‹œ ์ฝœ๋“œ (Cache Cold)์ƒˆ ์Šค๋ ˆ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ L1/L2์— ์—†์–ด ๋ฏธ์Šค ๋ˆ„์ 
ย TLB flush๊ฐ€์ƒโ†’๋ฌผ๋ฆฌ ๋งคํ•‘ ์บ์‹œ ๋ฌดํšจํ™”. ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋งŒ
ย ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€instruction pipelineยท๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ ๋ฌดํšจํ™”
ย PCID/ASIDTLB ์—”ํŠธ๋ฆฌ๋ฅผ ํ”„๋กœ์„ธ์Šค๋ณ„ ํƒœ๊น…ํ•ด flush ํšŒํ”ผ (ํ˜„๋Œ€ CPU)
๋น„๊ตํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ ๋น„์šฉ์Šค๋ ˆ๋“œ ์ „ํ™˜์ด 5~10๋ฐฐ ๋น ๋ฆ„ (TLBยทํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ณด์กด)
ย ์บ์‹œ ํžˆํŠธ์œจ๋กœ ๋ณธ ์Šค๋ ˆ๋“œ ์šฐ์œ„์Šค๋ ˆ๋“œ ์ „ํ™˜์€ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ์ฝ”๋“œยทํž™ยท์ „์—ญ ๋ฐ์ดํ„ฐ๊ฐ€ L1/L2/L3์— ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์–ด ์บ์‹œ ํžˆํŠธ์œจ ์œ ์ง€ โ†’ ์ฆ‰์‹œ ๋น ๋ฅธ ์‹คํ–‰. ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์€ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ๋ณ€๊ฒฝ์œผ๋กœ ์บ์‹œ ์ฝœ๋“œ + TLB flush โ†’ ์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๋ˆ„์ ๋˜๋ฉฐ ์Šค๋ ˆ๋“œ ์ „ํ™˜๋ณด๋‹ค ๋А๋ฆฐ ํ•ต์‹ฌ ์ด์œ 
์Šค์ผ€์ค„๋ง์„ ์ ํ˜• (Preemptive)ํƒ€์ด๋จธ๋กœ ๊ฐ•์ œ ์Šค์œ„์นญ. WindowsยทLinux ํ‘œ์ค€
ย ๋น„์„ ์ ํ˜•/ํ˜‘๋ ฅ์  (Cooperative)์ž๋ฐœ์  ์–‘๋ณด ์‹œ์—๋งŒ ์Šค์œ„์นญ. Fiberยท์˜ˆ์ „ Windows 3.1
ย Round-Robin๋ชจ๋“  ์Šค๋ ˆ๋“œ ๊ท ๋“ฑ time slice
ย ์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง์šฐ์„ ์ˆœ์œ„ ํฐ ์ˆœ. ๊ธฐ์•„(starvation) ์œ„ํ—˜
ย MLFQ (Multi-Level Feedback Queue)์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ/๋ฐฐ์น˜ ์ž๋™ ๋ถ„๋ฅ˜. WindowsยทLinux CFS์˜ ์„ ์กฐ
ย time slice (quantum)ํ•œ ์Šค๋ ˆ๋“œ์˜ ์—ฐ์† ์‹คํ–‰ ํ—ˆ์šฉ ์‹œ๊ฐ„. Windows ๊ธฐ๋ณธ ์•ฝ 15.6ms
Win32 ์Šค๋ ˆ๋“œCreateThread์ปค๋„ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ. ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…
ย SwitchToThread๊ฐ™์€ ์ฝ”์–ด์˜ ๋‹ค๋ฅธ Ready ์Šค๋ ˆ๋“œ๋กœ ์ฆ‰์‹œ ์–‘๋ณด
ย Sleep(0)๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ์Šค๋ ˆ๋“œ์— ์–‘๋ณด (์—†์œผ๋ฉด ์ฆ‰์‹œ ๋ณต๊ท€)
ย WaitForSingleObject์ปค๋„ ๊ฐ์ฒด(์ด๋ฒคํŠธยท๋ฎคํ…์Šคยท์„ธ๋งˆํฌ์–ด) ๋Œ€๊ธฐ
ย SuspendThread/ResumeThread์Šค๋ ˆ๋“œ ๊ฐ•์ œ ์ผ์‹œ์ •์ง€/์žฌ๊ฐœ (๋””๋ฒ„๊ฑฐยท์™ธ๋ถ€ ์ œ์–ด์šฉ)
Win32 ๋™๊ธฐํ™”Critical Section์‚ฌ์šฉ์ž ๋ชจ๋“œ spin โ†’ ๊ฒฝํ•ฉ ์‹œ ์ปค๋„ ์ง„์ž…. ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด๋งŒ
ย Mutex์ปค๋„ ๊ฐ์ฒด. ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ  ๊ฐ€๋Šฅ. ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…
ย Event / Semaphore์ปค๋„ ๊ฐ์ฒด. WaitForSingleObject๋กœ ๋Œ€๊ธฐ
ย SRWLock (Slim Reader/Writer)์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„  R/W lock. Vista+
ย Condition VariableSleepConditionVariableSRW. ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ 
ConcRT/PPLConcurrency RuntimeMSVC ์‚ฌ์šฉ์ž ๋ชจ๋“œ Task Scheduler (/cpp/parallel/concrt/)
ย Context::Block/Yield/Unblockํ˜‘๋ ฅ์  ์ปจํ…์ŠคํŠธ ์–‘๋ณด โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ
ย work stealingํ•œ๊ฐ€ํ•œ ์›Œ์ปค๊ฐ€ ๋‹ค๋ฅธ ํ์—์„œ ์ž‘์—… ํ›”์นจ
ย oversubscription์ฝ”์–ด ์ˆ˜๋ณด๋‹ค ๋งŽ์€ ์Šค๋ ˆ๋“œ ์˜๋„์  ์šด์šฉ
Fiber/UMSFiber (CreateFiber)์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์Šค์œ„์นญ. ์ปค๋„ ๋ชจ๋ฆ„
ย SwitchToFiberFiber ๊ฐ„ ์ง์ ‘ ์ „ํ™˜. ์ˆ˜์‹ญ nanosecond
ย UMS (User-Mode Scheduling)์ปค๋„ ์ธ์ง€ + ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์Šค์ผ€์ค„๋ง. Windows 7+/x64
C++ ํ‘œ์ค€std::threadWindows์—์„  _beginthreadex โ†’ CreateThread ๋งคํ•‘
ย std::mutexMSVC: SRWLock ๋˜๋Š” Critical Section ์œ„ ๊ตฌํ˜„
ย std::atomicCPU ๋ช…๋ น(LOCK XADDยทLOCK CMPXCHG). ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์Œ
ย std::condition_variableMSVC: Windows Condition Variable ์œ„
TLS__declspec(thread)MSVC TLS ๋ณ€์ˆ˜. ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ ์Šฌ๋กฏ
ย TlsAlloc/TlsGetValue๋™์  TLS ์Šฌ๋กฏ ๊ด€๋ฆฌ
ย TLS์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญTLS๋Š” ์Šค๋ ˆ๋“œ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์ฃผ โ†’ ์Šค์œ„์นญ ์‹œ ์ž๋™ ๋ณด์กด
CRT/MT (์ •์  CRT)CRT๋ฅผ exe์— ์ •์  ๋งํฌ. ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์•ˆ์ „ํŒ ์‚ฌ์šฉ
ย /MD (DLL CRT)CRT๋ฅผ DLL๋กœ ๋™์  ๋งํฌ. ๊ถŒ์žฅ (UCRT)
ย CRT ๋ฝ (_lock_file ๋“ฑ)stdioยทheap์ด ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฝ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์œ ๋ฐœ ๊ฐ€๋Šฅ
์–ธ๋ฆฌ์–ผGameThreadTickยทUObjectยทAActor ์ฒ˜๋ฆฌ. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ
ย RenderThreadGameThread ๋ช…๋ น ๋ฐ›์•„ RHI ๋ช…๋ น ์ƒ์„ฑ
ย RHIThreadGPU ๋“œ๋ผ์ด๋ฒ„ ํ˜ธ์ถœ ์ „๋‹ด (D3D12/Vulkan/Metal)
ย TaskGraph์˜์กด์„ฑ ๊ธฐ๋ฐ˜ ์ž‘์—… ๋ถ„ํ• . ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์ตœ์†Œํ™”
ย FRunnableThreadOS ์Šค๋ ˆ๋“œ ์ถ”์ƒํ™” โ€” ๋‚ด๋ถ€์ ์œผ๋กœ CreateThread
ย ENamedThreads์ž‘์—…์„ ์–ด๋А ์Šค๋ ˆ๋“œ์— ๋””์ŠคํŒจ์น˜ํ• ์ง€ ๋ช…์‹œ

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. ํ•œ ์ค„ ์ •์˜ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€
  3. ๋ฐœ์ƒ ์‹œ์  4๊ฐ€์ง€ โ€” ํƒ€์ด๋จธยท์‹œ์Šคํ…œ ์ฝœยท๋™๊ธฐํ™” ๋Œ€๊ธฐยท์ž๋ฐœ์  ์–‘๋ณด
  4. PCB/TCB ์ €์žฅยท๋ณต์› ๋‹จ๊ณ„ โ€” ๋ฌด์—‡์„ ์–ด๋””์— ์ €์žฅํ•˜๋‚˜
  5. ๋ชจ๋“œ ์Šค์œ„์น˜ โ‰  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ โ€” ์ž์ฃผ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ตฌ๋ถ„
  6. ๋น„์šฉ ์š”์†Œ โ€” ์บ์‹œ flush ยท TLB flush ยท ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€
  7. ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๋น„์šฉ ๋น„๊ต
  8. ์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ์˜ ์—ฐ๊ด€ โ€” ์„ ์ ํ˜•/๋น„์„ ์ ํ˜•/RR/์šฐ์„ ์ˆœ์œ„
  9. Windows ๊ด€์  โ€” Win32 ์Šค๋ ˆ๋“œ API์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ
  10. Windows ๋™๊ธฐํ™” ๊ฐ์ฒด๋ณ„ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ
  11. Concurrency Runtime / PPL โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์Šค์ผ€์ค„๋Ÿฌ
  12. Fiber API์™€ UMS โ€” ์ปค๋„ ๊ฐœ์ž… ์—†๋Š” ํ˜‘๋ ฅ์  ์Šค์œ„์นญ
  13. C++ ํ‘œ์ค€ ๋™์‹œ์„ฑ์˜ Windows ๋งคํ•‘
  14. Thread Local Storage์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ
  15. CRT ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์˜ต์…˜ โ€” /MT vs /MD
  16. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ โ€” GameThread/RenderThread/RHIThread
  17. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ
  18. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ (์žฌ๊ฒŒ์žฌ)
  19. ํšŒ๊ท€ ๋‹ค๋ฆฌ โ€” ๋‹ค๋ฅธ CS ํŒŒ์ผ ์—ฐ๊ฒฐ

1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ

30์ดˆ ๋‹ต๋ณ€

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ = CPU ์ฝ”์–ด์—์„œ ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” OS ์ž‘์—….
                  ํ˜„์žฌ ์ปจํ…์ŠคํŠธ(๋ ˆ์ง€์Šคํ„ฐยทSPยทPC)๋ฅผ PCB/TCB์— ์ €์žฅ โ†’ ๋‹ค์Œ ์ปจํ…์ŠคํŠธ ๋ณต์›.

๋ฐœ์ƒ ์‹œ์  4๊ฐ€์ง€:
  โ‘  ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ โ€” quantum ๋งŒ๋ฃŒ (์„ ์ ํ˜• ์Šค์ผ€์ค„๋ง)
  โ‘ก ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ โ€” read/recv/WaitForSingleObject
  โ‘ข ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ โ€” mutex/semaphore/event/condition variable
  โ‘ฃ ์ž๋ฐœ์  ์–‘๋ณด โ€” Sleep(0)/SwitchToThread/std::this_thread::yield

๋น„์šฉ ์š”์†Œ:
  โ‘  ๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์› (์ง์ ‘ ๋น„์šฉ, ์ˆ˜๋ฐฑ ns)
  โ‘ก ์บ์‹œ ์ฝœ๋“œ (๊ฐ„์ ‘ ๋น„์šฉ, ๊ฐ€์žฅ ํผ)
  โ‘ข TLB flush (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์—์„œ๋งŒ, PCID๋กœ ํšŒํ”ผ ๊ฐ€๋Šฅ)
  โ‘ฃ ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€ + ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ ๋ฌดํšจํ™”
  โ‘ค ์ปค๋„ ์ง„์ž…(๋ชจ๋“œ ์Šค์œ„์น˜) ์ž์ฒด ๋น„์šฉ

ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ:
  ์Šค๋ ˆ๋“œ ์ „ํ™˜ = TCB๋งŒ ๊ต์ฒด, ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ๋ณด์กด โ†’ 5~10๋ฐฐ ๋น ๋ฆ„
  ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ = CR3 ๊ต์ฒด + TLB flush + ์บ์‹œ ์ฝœ๋“œ

๋ชจ๋“œ ์Šค์œ„์น˜ โ‰  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜:
  ๋ชจ๋“œ ์Šค์œ„์น˜ = ๊ฐ™์€ ์Šค๋ ˆ๋“œ user โ†” kernel (PCB ๊ต์ฒด ์—†์Œ)
  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ = ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค๋กœ ๊ฐˆ์•„๋ผ์›€ (๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ)

Windows ๋น„์šฉ ์ŠคํŽ™ํŠธ๋Ÿผ (๋‚ฎ์Œ โ†’ ๋†’์Œ):
  Fiber/SwitchToFiber       ์‚ฌ์šฉ์ž ๋ชจ๋“œ, ์ˆ˜์‹ญ ns
  ConcRT Context::Yield     ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์ 
  SRWLock / Critical Section ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ , ๊ฒฝํ•ฉ ์‹œ ์ปค๋„
  Mutex / Event / Semaphore  ํ•ญ์ƒ ์ปค๋„ ๊ฐ์ฒด
  CreateThread quantum ๋งŒ๋ฃŒ  ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ โ†’ ์ปค๋„ ์Šค์ผ€์ค„๋Ÿฌ

๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋งต

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Context Switching
โ”œโ”€โ”€ ๋ฐœ์ƒ ์‹œ์  (์™œ ์ผ์–ด๋‚˜๋‚˜?)
โ”‚   โ”œโ”€โ”€ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ (์„ ์ )
โ”‚   โ”œโ”€โ”€ ๋ธ”๋กœํ‚น I/O / ์‹œ์Šคํ…œ ์ฝœ
โ”‚   โ”œโ”€โ”€ ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ (mutex/event)
โ”‚   โ””โ”€โ”€ ์ž๋ฐœ์  ์–‘๋ณด (yield/Sleep(0))
โ”œโ”€โ”€ PCB/TCB (๋ฌด์—‡์„ ์ €์žฅํ•˜๋‚˜?)
โ”‚   โ”œโ”€โ”€ PC, SP, ๋ฒ”์šฉ ๋ ˆ์ง€์Šคํ„ฐ, ํ”Œ๋ž˜๊ทธ
โ”‚   โ”œโ”€โ”€ FPU/SIMD ๋ ˆ์ง€์Šคํ„ฐ (lazy save)
โ”‚   โ”œโ”€โ”€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค (CR3 โ€” ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋งŒ)
โ”‚   โ””โ”€โ”€ ํ•ธ๋“ค ํ…Œ์ด๋ธ” (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋งŒ)
โ”œโ”€โ”€ ๋ชจ๋“œ ์Šค์œ„์น˜ vs ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
โ”‚   โ”œโ”€โ”€ ๋ชจ๋“œ ์Šค์œ„์น˜: user โ†” kernel (์Šค๋ ˆ๋“œ ๋™์ผ)
โ”‚   โ””โ”€โ”€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜: ์Šค๋ ˆ๋“œ ๊ต์ฒด (๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„)
โ”œโ”€โ”€ ๋น„์šฉ
โ”‚   โ”œโ”€โ”€ ์บ์‹œ ์ฝœ๋“œ โ€” ๊ฐ€์žฅ ํผ (๊ฐ„์ ‘)
โ”‚   โ”œโ”€โ”€ TLB flush โ€” ํ”„๋กœ์„ธ์Šค๋งŒ (PCID๋กœ ํšŒํ”ผ)
โ”‚   โ”œโ”€โ”€ ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€ยท๋ถ„๊ธฐ ์˜ˆ์ธก ๋ฌดํšจํ™”
โ”‚   โ””โ”€โ”€ ์ปค๋„ ์ง„์ž… ์ž์ฒด
โ”œโ”€โ”€ ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ (5~10๋ฐฐ ์ฐจ์ด)
โ”‚   โ””โ”€โ”€ 19๋ฒˆ ํšŒ๊ท€
โ”œโ”€โ”€ ์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜
โ”‚   โ”œโ”€โ”€ ์„ ์ ํ˜• vs ๋น„์„ ์ ํ˜•
โ”‚   โ”œโ”€โ”€ Round-Robin / ์šฐ์„ ์ˆœ์œ„ / MLFQ
โ”‚   โ”œโ”€โ”€ time slice (Windows ๊ธฐ๋ณธ ~15.6ms)
โ”‚   โ””โ”€โ”€ ์งง์œผ๋ฉด ์‘๋‹ต์„ฑโ†‘ยท์˜ค๋ฒ„ํ—ค๋“œโ†‘ / ๊ธธ๋ฉด throughputโ†‘ยท์‘๋‹ต์„ฑโ†“
โ”œโ”€โ”€ Windows ๊นŠ์ด (MSVC ๋ฌธ์„œ ํŠธ๋ฆฌ)
โ”‚   โ”œโ”€โ”€ Win32 ์Šค๋ ˆ๋“œ API
โ”‚   โ”‚   โ”œโ”€โ”€ CreateThread (์ปค๋„ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ)
โ”‚   โ”‚   โ”œโ”€โ”€ SwitchToThread / Sleep(0) (์ž๋ฐœ ์–‘๋ณด)
โ”‚   โ”‚   โ”œโ”€โ”€ WaitForSingleObject (๋ธ”๋กœํ‚น)
โ”‚   โ”‚   โ””โ”€โ”€ SuspendThread / ResumeThread
โ”‚   โ”œโ”€โ”€ ๋™๊ธฐํ™” ๊ฐ์ฒด ๋น„์šฉ ์ŠคํŽ™ํŠธ๋Ÿผ
โ”‚   โ”‚   โ”œโ”€โ”€ Critical Section (์‚ฌ์šฉ์ž ์šฐ์„ , ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋งŒ)
โ”‚   โ”‚   โ”œโ”€โ”€ SRWLock (์‚ฌ์šฉ์ž ์šฐ์„ , R/W ๋ถ„๋ฆฌ)
โ”‚   โ”‚   โ”œโ”€โ”€ Condition Variable (์‚ฌ์šฉ์ž ์šฐ์„ )
โ”‚   โ”‚   โ””โ”€โ”€ Mutex/Event/Semaphore (ํ•ญ์ƒ ์ปค๋„)
โ”‚   โ”œโ”€โ”€ ConcRT/PPL โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ Task Scheduler
โ”‚   โ”‚   โ”œโ”€โ”€ Context::Block/Yield/Unblock
โ”‚   โ”‚   โ”œโ”€โ”€ work stealing
โ”‚   โ”‚   โ””โ”€โ”€ oversubscription
โ”‚   โ”œโ”€โ”€ Fiber API
โ”‚   โ”‚   โ”œโ”€โ”€ CreateFiber / SwitchToFiber
โ”‚   โ”‚   โ””โ”€โ”€ ์ปค๋„ ๋ชจ๋ฆ„ โ€” ํ˜‘๋ ฅ์  ์Šค์œ„์นญ
โ”‚   โ”œโ”€โ”€ UMS (User-Mode Scheduling)
โ”‚   โ”œโ”€โ”€ C++ ํ‘œ์ค€์˜ Windows ๋งคํ•‘
โ”‚   โ”‚   โ”œโ”€โ”€ std::thread โ†’ _beginthreadex โ†’ CreateThread
โ”‚   โ”‚   โ”œโ”€โ”€ std::mutex โ†’ SRWLock or Critical Section
โ”‚   โ”‚   โ””โ”€โ”€ std::condition_variable โ†’ Condition Variable
โ”‚   โ”œโ”€โ”€ TLS โ€” ์Šค๋ ˆ๋“œ๋ณ„ ๋ฉ”๋ชจ๋ฆฌ, ์Šค์œ„์นญ ์‹œ ์ž๋™ ๋ณด์กด
โ”‚   โ”‚   โ”œโ”€โ”€ __declspec(thread)
โ”‚   โ”‚   โ””โ”€โ”€ TlsAlloc / TlsGetValue
โ”‚   โ””โ”€โ”€ CRT ์˜ต์…˜
โ”‚       โ”œโ”€โ”€ /MT (์ •์  CRT)
โ”‚       โ”œโ”€โ”€ /MD (DLL CRT, UCRT)
โ”‚       โ””โ”€โ”€ stdio/heap ๋ฝ โ€” ์˜๋„์น˜ ์•Š์€ ์Šค์œ„์นญ ์œ ๋ฐœ
โ””โ”€โ”€ ์–ธ๋ฆฌ์–ผ
    โ”œโ”€โ”€ GameThread (Tick, UObject)
    โ”œโ”€โ”€ RenderThread (RHI ๋ช…๋ น)
    โ”œโ”€โ”€ RHIThread (GPU ๋“œ๋ผ์ด๋ฒ„)
    โ”œโ”€โ”€ TaskGraph (์˜์กด์„ฑ ๊ธฐ๋ฐ˜)
    โ”œโ”€โ”€ FRunnableThread (OS ์Šค๋ ˆ๋“œ ์ถ”์ƒํ™”)
    โ””โ”€โ”€ ENamedThreads โ€” ๋””์ŠคํŒจ์น˜ ์œ„์น˜ ๋ช…์‹œ

2. ํ•œ ์ค„ ์ •์˜ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ CPU ์ฝ”์–ด ์œ„์—์„œ ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ(๋˜๋Š” ํ”„๋กœ์„ธ์Šค)๋ฅผ ์ž ์‹œ ๋‚ด๋ ค๋†“๊ณ , ๋‹ค๋ฅธ ์‹คํ–‰ ๋‹จ์œ„๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” OS์˜ ํ•ต์‹ฌ ์ž‘์—…์ž…๋‹ˆ๋‹ค.

โ€œ์ปจํ…์ŠคํŠธโ€๋Š” ์ •ํ™•ํžˆ ๋ฌด์—‡์ธ๊ฐ€

์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰์„ ์ž ์‹œ ๋ฉˆ์ท„๋‹ค๊ฐ€ ์ •ํ™•ํžˆ ๊ทธ ์ž๋ฆฌ์—์„œ ์žฌ๊ฐœํ•˜๋ ค๋ฉด, CPU์˜ ๋ชจ๋“  ํœ˜๋ฐœ์„ฑ ์ƒํƒœ๋ฅผ ๋น ์ง์—†์ด ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ์ปจํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
์ปจํ…์ŠคํŠธ์˜ ๊ตฌ์„ฑ (x86_64 ๊ธฐ์ค€):
  โ”œโ”€ ๋ฒ”์šฉ ๋ ˆ์ง€์Šคํ„ฐ (GPR): rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8~r15  (16๊ฐœ ร— 8B)
  โ”œโ”€ ๋ช…๋ น ํฌ์ธํ„ฐ:        rip (= PC)
  โ”œโ”€ ํ”Œ๋ž˜๊ทธ ๋ ˆ์ง€์Šคํ„ฐ:    rflags
  โ”œโ”€ ์„ธ๊ทธ๋จผํŠธ ๋ ˆ์ง€์Šคํ„ฐ:  cs, ds, ss, es, fs, gs
  โ”œโ”€ FPU/MMX ๋ ˆ์ง€์Šคํ„ฐ:   st0~st7 (๊ฐ 80bit)
  โ”œโ”€ SIMD ๋ ˆ์ง€์Šคํ„ฐ:      xmm0~xmm15 (128bit), ymm0~15 (256bit), zmm0~31 (512bit AVX-512)
  โ””โ”€ (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ์‹œ) ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค: cr3

์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ๋งŒ ๋”ฐ์ ธ๋„ ํ•œ ํšŒ๋‹น ์ˆ˜๋ฐฑ ๋ฐ”์ดํŠธ~์ˆ˜ KB๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋กœ ์˜ค๊ฐ‘๋‹ˆ๋‹ค. AVX-512๊ฐ€ ํ™œ์„ฑํ™”๋œ ์ฝ”๋“œ๋Š” ZMM ๋ ˆ์ง€์Šคํ„ฐ๋งŒ 32ร—64B = 2KB๋ผ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋” ๋ฌด๊ฑฐ์›Œ์ง€๋ฏ€๋กœ, OS๋Š” ๋ณดํ†ต lazy save(ํ•„์š”ํ•  ๋•Œ๋งŒ ์ €์žฅ) ์ •์ฑ…์„ ์”๋‹ˆ๋‹ค.

ํ๋ฆ„ ํ•œ๋ˆˆ์—

1
2
3
4
5
6
7
8
9
10
11
์Šค๋ ˆ๋“œ A ์‹คํ–‰ ์ค‘
  โ†“ (ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ / ๋ธ”๋กœํ‚น / yield)
์‚ฌ์šฉ์ž ๋ชจ๋“œ โ†’ ์ปค๋„ ๋ชจ๋“œ (๋ชจ๋“œ ์Šค์œ„์น˜)
  โ†“
์Šค์ผ€์ค„๋Ÿฌ: A์˜ ์ปจํ…์ŠคํŠธ โ†’ A์˜ TCB์— ์ €์žฅ
์Šค์ผ€์ค„๋Ÿฌ: ๋‹ค์Œ ํ›„๋ณด B ์„ ํƒ (์šฐ์„ ์ˆœ์œ„ยทtime sliceยทaffinity ๊ณ ๋ ค)
์Šค์ผ€์ค„๋Ÿฌ: B์˜ TCB์—์„œ ์ปจํ…์ŠคํŠธ ๋ณต์›
  โ†“ (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์ด๋ฉด cr3 ๊ต์ฒด โ†’ TLB flush)
์ปค๋„ ๋ชจ๋“œ โ†’ ์‚ฌ์šฉ์ž ๋ชจ๋“œ (๋ชจ๋“œ ์Šค์œ„์น˜)
  โ†“
์Šค๋ ˆ๋“œ B ์‹คํ–‰ ์žฌ๊ฐœ (B๊ฐ€ ๋ฉˆ์ท„๋˜ ์ž๋ฆฌ๋ถ€ํ„ฐ)

์ด ์ „์ฒด ๊ณผ์ •์ด ์ผ๋ฐ˜์ ์œผ๋กœ 1~10ฮผs ์‚ฌ์ด์ž…๋‹ˆ๋‹ค. ์ง์ ‘ ๋น„์šฉ์€ ๋ณดํ†ต 0.5~1ฮผs, ๋‚˜๋จธ์ง€๋Š” ์บ์‹œยทTLB ์ฝœ๋“œ ๋น„์šฉ์ž…๋‹ˆ๋‹ค.

์™œ ํ•„์š”ํ•œ๊ฐ€

CPU ์ฝ”์–ด๋Š” ํ•œ ์ˆœ๊ฐ„์— ํ•˜๋‚˜์˜ ๋ช…๋ น ํ๋ฆ„๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(SMT/ํ•˜์ดํผ์Šค๋ ˆ๋”ฉ์ด ์žˆ์–ด๋„ ๋ณธ์งˆ์€ ๊ฐ™์Œ). ๊ทธ๋Ÿฐ๋ฐ OS๋Š” ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋™์‹œ์— ์‚ด์•„ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋น ๋ฅด๊ฒŒ ๋Œ์•„๊ฐ€๋ฉฐ ์‹œ๊ฐ„์„ ์ชผ๊ฐœ ์“ฐ๋Š” ๋ชจ๋ธ, ์ฆ‰ ์‹œ๋ถ„ํ• (time-sharing) ์ด ํ•„์š”ํ•˜๊ณ , ๊ทธ ์‹œ๋ถ„ํ• ์˜ ๋ณธ์ฒด๊ฐ€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ž…๋‹ˆ๋‹ค.

19๋ฒˆ์—์„œ โ€œ์Šค๋ ˆ๋“œ ์ „ํ™˜์ด 5~10๋ฐฐ ๋น ๋ฅด๋‹คโ€๊ณ  ํ–ˆ๋Š”๋ฐ, ๊ทธ ์ฐจ์ด์˜ ์›์ธ์ด 21๋ฒˆ์—์„œ ์„ค๋ช…ํ•  ๋น„์šฉ ์š”์†Œ๋“ค์ž…๋‹ˆ๋‹ค.


3. ๋ฐœ์ƒ ์‹œ์  4๊ฐ€์ง€ โ€” ํƒ€์ด๋จธยท์‹œ์Šคํ…œ ์ฝœยท๋™๊ธฐํ™” ๋Œ€๊ธฐยท์ž๋ฐœ์  ์–‘๋ณด

๋ฐœ์ƒ ์‹œ์  1 โ€” ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ (Timer Interrupt)

OS๊ฐ€ ์Šค๋ ˆ๋“œ์— ํ• ๋‹นํ•œ time slice (quantum, ์‹œ๊ฐ„ ์กฐ๊ฐ) ๊ฐ€ ๋งŒ๋ฃŒ๋˜๋ฉด ํ•˜๋“œ์›จ์–ด ํƒ€์ด๋จธ๊ฐ€ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , OS ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๊ฐ•์ œ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ผ์œผํ‚ต๋‹ˆ๋‹ค. ์„ ์ ํ˜•(preemptive) ์Šค์ผ€์ค„๋ง์˜ ๋ณธ์ฒด์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
์‹œ๊ฐ„์ถ• โ†’
์Šค๋ ˆ๋“œ A: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ (time slice 15.6ms ์†Œ์ง„)
                       โ†‘ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ
                       โ†“ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
์Šค๋ ˆ๋“œ B:              โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ (๋‹ค์Œ quantum)

Windows์˜ ๊ธฐ๋ณธ quantum์€ ์•ฝ 15.6ms(Server๋Š” ๋” ๊น€), ๋ฉ€ํ‹ฐ๋ฏธ๋””์–ด ํƒ€์ด๋จธ API(timeBeginPeriod(1))๋กœ ์ตœ์†Œ 1ms๊นŒ์ง€ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์งง์„์ˆ˜๋ก ์‘๋‹ต์„ฑ์ด ์ข‹์•„์ง€์ง€๋งŒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋นˆ๋„๊ฐ€ ๋Š˜์–ด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ˆ„์ ๋ฉ๋‹ˆ๋‹ค.

๋ฐœ์ƒ ์‹œ์  2 โ€” ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ (Blocking System Call)

๋Œ€๊ธฐ๋ฅผ ๋™๋ฐ˜ํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ์„ ๋งŒ๋‚˜๋ฉด ๊ทธ ์Šค๋ ˆ๋“œ๋Š” ์ฆ‰์‹œ Wait ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๊ณ , ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค๋ฅธ Ready ์Šค๋ ˆ๋“œ๋ฅผ ๊ณจ๋ผ ๋””์ŠคํŒจ์น˜ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Windows
DWORD result = WaitForSingleObject(hEvent, INFINITE);
// ํ˜ธ์ถœ ์ฆ‰์‹œ โ†’ Wait ์ƒํƒœ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ โ†’ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ์‹คํ–‰
// hEvent ์‹œ๊ทธ๋„ โ†’ Ready ํ โ†’ ์Šค์ผ€์ค„๋ง โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋กœ ๋ณต๊ท€

// ํŒŒ์ผ I/O
HANDLE hFile = CreateFile(...);
DWORD bytesRead;
ReadFile(hFile, buffer, 1024, &bytesRead, NULL);
// ๋””์Šคํฌ ์‘๋‹ต ๋Œ€๊ธฐ โ†’ Wait โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

// ๋„คํŠธ์›Œํฌ I/O (๋™๊ธฐ ๋ชจ๋“œ)
recv(socket, buffer, 1024, 0);
// ์ˆ˜์‹  ๋ฐ์ดํ„ฐ ๋„์ฐฉ๊นŒ์ง€ โ†’ Wait โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

์ด ๊ฒฝ์šฐ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ–‰์œ„์ž…๋‹ˆ๋‹ค. CPU๊ฐ€ ๋””์Šคํฌ๋‚˜ ๋„คํŠธ์›Œํฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ๋†€๊ฒŒ ๋‘๋Š” ๋Œ€์‹  ๋‹ค๋ฅธ ์ผ์„ ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒŒ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์˜ ๋ณธ์งˆ์ด๋‹ˆ๊นŒ์š”.

๋ฐœ์ƒ ์‹œ์  3 โ€” ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ

mutexยทsemaphoreยทeventยทcondition variable์—์„œ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ์˜ ํ•œ ํ˜•ํƒœ์ง€๋งŒ, ๋ฐœ์ƒ ๋นˆ๋„์™€ ํŒจํ„ด์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

1
2
3
4
5
std::mutex m;
std::lock_guard<std::mutex> lock(m);  // ๋ฝ์ด ์žกํ˜€์žˆ์œผ๋ฉด โ†’ Wait โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

std::condition_variable cv;
cv.wait(lock, []{ return ready; });   // ์กฐ๊ฑด false๋ฉด โ†’ Wait โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

Windows์˜ Critical Section๊ณผ SRWLock์€ ์ฒ˜์Œ์— ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์ž ๊น spinํ•˜๋‹ค๊ฐ€ ๊ทธ๋ž˜๋„ ๋ชป ์žก์œผ๋ฉด ๊ทธ๋•Œ ์ปค๋„์— ์ง„์ž…ํ•ด Wait ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ์ด๊ฒŒ โ€œ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ โ€ ๋™๊ธฐํ™” ๊ฐ์ฒด์˜ ํ•ต์‹ฌ์œผ๋กœ, ๊ฒฝํ•ฉ์ด ์—†๋Š” ์ผ๋ฐ˜์  ์ผ€์ด์Šค์—์„  ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์ด ๋ฝ ํš๋“์ด ๋๋‚ฉ๋‹ˆ๋‹ค.

๋ฐœ์ƒ ์‹œ์  4 โ€” ์ž๋ฐœ์  ์–‘๋ณด (Voluntary Yield)

์Šค๋ ˆ๋“œ๊ฐ€ ์ง์ ‘ โ€œ์ง€๊ธˆ CPU๋ฅผ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ๋„˜๊ธฐ๊ฒ ๋‹คโ€๊ณ  OS์— ์•Œ๋ฆฌ๋Š” ํ˜ธ์ถœ์ž…๋‹ˆ๋‹ค. ํ˜‘๋ ฅ์  ์Šค์ผ€์ค„๋ง์˜ ํŒจํ„ด์ด์ง€๋งŒ, ์„ ์ ํ˜• OS์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
// Windows
SwitchToThread();         // ๊ฐ™์€ ์ฝ”์–ด์˜ ๋‹ค๋ฅธ Ready ์Šค๋ ˆ๋“œ์— ์–‘๋ณด. ์—†์œผ๋ฉด ์ฆ‰์‹œ ๋ณต๊ท€
Sleep(0);                 // ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ์Šค๋ ˆ๋“œ์— ์–‘๋ณด. ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋Š” ํ•ญ์ƒ ์„ ์ 
Sleep(1);                 // ์ตœ์†Œ 1ms ๋Œ€๊ธฐ (์‹ค์ œ๋ก  quantum ๋‹จ์œ„๋กœ ๋ฐ˜์˜ฌ๋ฆผ)

// C++ ํ‘œ์ค€
std::this_thread::yield();        // ๊ตฌํ˜„์ฒด๊ฐ€ ์ ์ ˆํ•œ OS ํ˜ธ์ถœ๋กœ ๋งคํ•‘
std::this_thread::sleep_for(...);

Sleep(0)๊ณผ SwitchToThread์˜ ์ฐจ์ด๋Š” ์–ด๋–ค ์Šค๋ ˆ๋“œ๊นŒ์ง€ ํ›„๋ณด๋กœ ๋ณด๋А๋ƒ์ž…๋‹ˆ๋‹ค. Sleep(0)์€ ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ํ•œ์ •, SwitchToThread๋Š” ๊ฐ™์€ ์ฝ”์–ด์˜ ๋ชจ๋“  Ready ์Šค๋ ˆ๋“œ(์šฐ์„ ์ˆœ์œ„ ๋ฌด๊ด€). spin lock์—์„œ ๊ฒฝํ•ฉ ์‹œ _mm_pause() ๋˜๋Š” SwitchToThread๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์–‘๋ณดํ•˜๋Š” ํŒจํ„ด์ด ํ”ํ•ฉ๋‹ˆ๋‹ค.

4์‹œ์  ๋น„๊ต ํ‘œ

๋ฐœ์ƒ ์‹œ์ ํŠธ๋ฆฌ๊ฑฐ๋ชจ๋“œ๋นˆ๋„๋น„์šฉ
ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธํ•˜๋“œ์›จ์–ด quantum ๋งŒ๋ฃŒ๊ฐ•์ œ(์„ ์ )๋ณดํ†ต (์ˆ˜์‹ญ Hz)๋ณดํ†ต
๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœI/OยทํŒŒ์ผยท์†Œ์ผ“์Šค๋ ˆ๋“œ ์ž๋ฐœ โ†’ ์ปค๋„ ๊ฐ•์ œ์žฆ์Œ๋ณดํ†ต
๋™๊ธฐํ™” ๋Œ€๊ธฐmutexยทevent ๋“ฑ์ž๋ฐœ โ†’ ์ปค๋„ (๊ฒฝํ•ฉ ์‹œ)์ฝ”๋“œ ์˜์กด์‚ฌ์šฉ์ž ๋ชจ๋“œ๋ฉด ์ž‘์Œ
์ž๋ฐœ์  ์–‘๋ณดyieldยทSleep(0)์ž๋ฐœ์ฝ”๋“œ ์˜์กด๊ฐ€์žฅ ์ž‘์Œ

4. PCB/TCB ์ €์žฅยท๋ณต์› ๋‹จ๊ณ„ โ€” ๋ฌด์—‡์„ ์–ด๋””์— ์ €์žฅํ•˜๋‚˜

PCB์™€ TCB์˜ ์—ญํ•  ๊ตฌ๋ถ„

19๋ฒˆ์—์„œ ์ •๋ฆฌํ•œ ๊ทธ๋Œ€๋กœ์ง€๋งŒ, ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์—์„œ ๋‘˜์ด ์–ด๋–ป๊ฒŒ ์“ฐ์ด๋Š”์ง€ ๋” ์ž์„ธํžˆ ๋ด…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PCB (Process Control Block) โ€” ํ”„๋กœ์„ธ์Šค 1๊ฐœ๋‹น 1๊ฐœ
  โ”œโ”€ PID
  โ”œโ”€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค (cr3 ๊ฐ’)
  โ”œโ”€ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ์ •๋ณด (์ฝ”๋“œ/๋ฐ์ดํ„ฐ/ํž™ ์˜์—ญ ๋งคํ•‘)
  โ”œโ”€ ํ•ธ๋“ค ํ…Œ์ด๋ธ” (ํŒŒ์ผยท์†Œ์ผ“ยท์ด๋ฒคํŠธ ๋“ฑ)
  โ”œโ”€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ๋ถ€๋ชจ/์ž์‹ PID
  โ”œโ”€ ๋ณด์•ˆ ํ† ํฐ (Windows: ์‚ฌ์šฉ์ž/๊ทธ๋ฃน/๊ถŒํ•œ)
  โ””โ”€ ์†Œ์† TCB ๋ฆฌ์ŠคํŠธ

TCB (Thread Control Block) โ€” ์Šค๋ ˆ๋“œ 1๊ฐœ๋‹น 1๊ฐœ
  โ”œโ”€ TID
  โ”œโ”€ ๋ ˆ์ง€์Šคํ„ฐ ์ปจํ…์ŠคํŠธ (PC, SP, GPR, ํ”Œ๋ž˜๊ทธ, FPU/SIMD)
  โ”œโ”€ ์Šคํƒ ๋ฒ ์ด์Šค ์ฃผ์†Œ + ํฌ๊ธฐ (์ž๊ธฐ ์Šคํƒ์˜ ์œ„์น˜)
  โ”œโ”€ ์šฐ์„ ์ˆœ์œ„, ์ƒํƒœ (Running/Ready/Wait)
  โ”œโ”€ TLS ์Šฌ๋กฏ ํฌ์ธํ„ฐ
  โ”œโ”€ ์‹œ๊ทธ๋„ ๋งˆ์Šคํฌ / SEH ์ฒด์ธ
  โ””โ”€ ์†Œ์† PCB ํฌ์ธํ„ฐ

์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๋‹จ๊ณ„ (๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด)

1
2
3
4
5
6
7
8
9
10
11
12
13
1. ํŠธ๋ฆฌ๊ฑฐ (ํƒ€์ด๋จธ/์‹œ์Šคํ…œ ์ฝœ/๋™๊ธฐํ™” ๋Œ€๊ธฐ/yield)
2. CPU๊ฐ€ ์ž๋™์œผ๋กœ ํŠธ๋žฉ โ†’ ์ปค๋„ ๋ชจ๋“œ ์ง„์ž…
3. ์ปค๋„ ์ง„์ž… ์‹œ ์ผ๋ถ€ ๋ ˆ์ง€์Šคํ„ฐ ์ž๋™ ์ €์žฅ (CPU์˜ trap frame ๋ฉ”์ปค๋‹ˆ์ฆ˜)
4. ์Šค์ผ€์ค„๋Ÿฌ ์ง„์ž…
5. ํ˜„์žฌ ์Šค๋ ˆ๋“œ A์˜ TCB์—:
     - ๋ ˆ์ง€์Šคํ„ฐ ์ปจํ…์ŠคํŠธ ์ €์žฅ (PC, SP, GPR, ํ”Œ๋ž˜๊ทธ)
     - FPU/SIMD๋Š” lazy save (์‚ฌ์šฉํ–ˆ์œผ๋ฉด)
6. ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค์Œ ์Šค๋ ˆ๋“œ B ์„ ํƒ
     - ์šฐ์„ ์ˆœ์œ„, time slice ์ž”๋Ÿ‰, CPU affinity, NUMA ๋…ธ๋“œ ๊ณ ๋ ค
7. ์Šค๋ ˆ๋“œ B์˜ TCB์—์„œ:
     - ๋ ˆ์ง€์Šคํ„ฐ ์ปจํ…์ŠคํŠธ ๋ณต์›
     - SP๋ฅผ B์˜ ์Šคํƒ์œผ๋กœ ๊ต์ฒด โ† ์ด ์‹œ์ ๋ถ€ํ„ฐ B์˜ ์Šคํƒ์ด ํ™œ์„ฑ
8. ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋ณต๊ท€ (rip๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ช…๋ น๋ถ€ํ„ฐ ์žฌ๊ฐœ)

ํ•ต์‹ฌ์€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”ยทํ•ธ๋“ค ํ…Œ์ด๋ธ”ยท๋ฉ”๋ชจ๋ฆฌ๋งต์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ์Šค๋ ˆ๋“œ๋“ค์€ ๊ฐ™์€ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๋ฏ€๋กœ cr3๊ฐ€ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ์„ธ์Šค ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๋‹จ๊ณ„ (๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๋กœ)

1
2
3
4
5
6
7
8
1~6. (์œ„์™€ ๋™์ผ)
7. ์ƒˆ ํ”„๋กœ์„ธ์Šค P2์˜ PCB์—์„œ:
     - ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค (cr3) ๊ต์ฒด  โ† ์ด๊ฒŒ ์ถ”๊ฐ€
     - TLB flush (๋˜๋Š” PCID ํƒœ๊น…์œผ๋กœ ํšŒํ”ผ)
     - ํ•ธ๋“ค ํ…Œ์ด๋ธ” ํฌ์ธํ„ฐ ๊ต์ฒด
     - ๋ณด์•ˆ ํ† ํฐ ๊ต์ฒด
8. P2์˜ ์ฒซ ์Šค๋ ˆ๋“œ B์˜ TCB ๋ณต์› (์œ„์™€ ๋™์ผ)
9. ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋ณต๊ท€

์ถ”๊ฐ€๋˜๋Š” ๋‹จ๊ณ„๋Š” cr3 ๊ต์ฒด์™€ ๊ทธ์— ๋”ฐ๋ฅธ TLB flush๊ฐ€ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์ด๊ฒŒ 5~10๋ฐฐ ๋น„์šฉ ์ฐจ์ด์˜ ์ง์ ‘ ์›์ธ์ž…๋‹ˆ๋‹ค.

lazy FPU save โ€” ๋น„์šฉ ์ ˆ๊ฐ ํŠธ๋ฆญ

FPU/SIMD ๋ ˆ์ง€์Šคํ„ฐ๋Š” ์–‘๋„ ๋งŽ๊ณ (AVX-512๋ฉด 2KB), ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์“ฐ์ง„ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ OS๋Š” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์‹œ FPU ์‚ฌ์šฉ ๋น„ํŠธ๋งŒ ๋„๊ณ  ์‹ค์ œ ์ €์žฅ์€ ๋ฏธ๋ฃน๋‹ˆ๋‹ค. ๋‹ค์Œ ์Šค๋ ˆ๋“œ๊ฐ€ FPU ๋ช…๋ น์„ ์ฒ˜์Œ ์“ฐ๋Š” ์ˆœ๊ฐ„ ํŠธ๋žฉ์ด ๊ฑธ๋ฆฌ๊ณ , ๊ทธ๋•Œ ์ด์ „ ์Šค๋ ˆ๋“œ์˜ FPU ์ปจํ…์ŠคํŠธ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ƒˆ ์Šค๋ ˆ๋“œ์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
์Šค๋ ˆ๋“œ A: FPU ์‚ฌ์šฉ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์‹œ FPU ์‚ฌ์šฉ ๋น„ํŠธ๋งŒ ๋”
์Šค๋ ˆ๋“œ B: FPU ์•ˆ ์”€ โ†’ FPU ์ปจํ…์ŠคํŠธ ์•ˆ ๋งŒ์ง (์ด๋“)
์Šค๋ ˆ๋“œ B: FPU ๋ช…๋ น ๋งŒ๋‚จ โ†’ ํŠธ๋žฉ โ†’ ๊ทธ๋•Œ A์˜ FPU ์ €์žฅ + B์˜ FPU ๋ณต์›

๋Œ€๋ถ€๋ถ„์˜ ์›Œํฌ๋กœ๋“œ์—์„œ FPU๋ฅผ ์“ฐ๋Š” ์Šค๋ ˆ๋“œ ์ˆ˜๊ฐ€ ์ ์–ด์„œ ์ด ์ตœ์ ํ™”๊ฐ€ ํฐ ํšจ๊ณผ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค. ๋‹จ ๊ฒŒ์ž„์ฒ˜๋Ÿผ ๊ฑฐ์˜ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ SIMD๋ฅผ ์“ฐ๋ฉด lazy save์˜ ์ด๋“์ด ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.


5. ๋ชจ๋“œ ์Šค์œ„์น˜ โ‰  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ โ€” ์ž์ฃผ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ตฌ๋ถ„

์ •์˜ ์ฐจ์ด

ํ•ญ๋ชฉ๋ชจ๋“œ ์Šค์œ„์น˜ (Mode Switch)์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ (Context Switch)
๋ฌด์—‡์ด ๋ฐ”๋€Œ๋‚˜CPU ๋ชจ๋“œ (user โ†” kernel)์‹คํ–‰ ์ฃผ์ฒด (์Šค๋ ˆ๋“œ A โ†’ ์Šค๋ ˆ๋“œ B)
์Šค๋ ˆ๋“œ ๋™์ผ์„ฑ๊ฐ™์Œ๋‹ค๋ฆ„ (๋˜๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค)
PCB/TCB ๊ต์ฒด์—†์Œ์žˆ์Œ
TLB flush์—†์Œ์žˆ์Œ (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋งŒ)
์บ์‹œ ์ฝœ๋“œ๊ฑฐ์˜ ์—†์Œํผ (๊ฐ„์ ‘ ๋น„์šฉ์˜ ํ•ต์‹ฌ)
๋น„์šฉ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ ns์ˆ˜๋ฐฑ ns~์ˆ˜ ฮผs (+ ์บ์‹œ ์ฝœ๋“œ)
๊ด€๊ณ„์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ ์ผ์–ด๋‚จ๋ชจ๋“œ ์Šค์œ„์น˜๋Š” ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์ด๋„ ์ผ์–ด๋‚จ

๋ชจ๋“œ ์Šค์œ„์น˜๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ

CPU๋Š” ๋‹ค์Œ ๋„ค ๊ฐ€์ง€ ์‚ฌ๊ฑด์—์„œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ โ†’ ์ปค๋„ ๋ชจ๋“œ๋กœ ์ž๋™ ์ง„์ž…ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ฝ”๋“œ๊ฐ€ ์ง์ ‘ โ€œ์ง€๊ธˆ๋ถ€ํ„ฐ ์ปค๋„ ๋ชจ๋“œโ€๋ผ๊ณ  ์„ ์–ธํ•  ์ˆ˜๋Š” ์—†๊ณ , ํ•˜๋“œ์›จ์–ด๊ฐ€ ๊ฐ•์ œ๋กœ ๋ชจ๋“œ๋ฅผ ์˜ฌ๋ฆฐ๋‹ค๋Š” ๊ฒŒ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ์˜ˆ์‹œ๋ˆ„๊ฐ€ ๋ฐœ์ƒ์‹œํ‚ค๋‚˜
์‹œ์Šคํ…œ ์ฝœ (System Call)read()ยทwrite()ยทCreateFile()ยทWaitForSingleObject()ยทmmap()์‚ฌ์šฉ์ž ์ฝ”๋“œ (syscall/int 0x80 ๋ช…๋ น)
ํ•˜๋“œ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ (Hardware Interrupt)ํƒ€์ด๋จธยทํ‚ค๋ณด๋“œยท๋งˆ์šฐ์Šคยท๋””์Šคํฌ ์™„๋ฃŒยท๋„คํŠธ์›Œํฌ ํŒจํ‚ท ์ˆ˜์‹ ์™ธ๋ถ€ ์žฅ์น˜ (CPU์˜ INTR ํ•€)
์˜ˆ์™ธ (Exception/Trap)Page FaultยทDivide by ZeroยทInvalid OpcodeยทGeneral Protection FaultCPU ์ž์ฒด (๋ช…๋ น ์‹คํ–‰ ๋„์ค‘ ๊ฐ์ง€)
์†Œํ”„ํŠธ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ๋””๋ฒ„๊ฑฐ breakpoint(int 3), ๋ช…์‹œ์  ํŠธ๋žฉ ๋ช…๋ น์‚ฌ์šฉ์ž/๋””๋ฒ„๊ฑฐ ์ฝ”๋“œ

์ง„์ž… ์งํ›„ CPU๋Š” trap frame(ํ˜„์žฌ RIPยทRSPยทRFLAGS ๋“ฑ)์„ ์ปค๋„ ์Šคํƒ์— ์ž๋™ ์ €์žฅํ•˜๊ณ , IDT(Interrupt Descriptor Table)์— ๋“ฑ๋ก๋œ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ ํ”„ํ•ฉ๋‹ˆ๋‹ค. ๊ถŒํ•œ ๋น„ํŠธ(CS ๋ ˆ์ง€์Šคํ„ฐ์˜ RPL)๋Š” 0(์ปค๋„)์œผ๋กœ ๋ฐ”๋€๋‹ˆ๋‹ค.

์ปค๋„ โ†’ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ๋ณต๊ท€๋Š” ๊ทธ ๋ฐ˜๋Œ€ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค. iret(์ธํ„ฐ๋ŸฝํŠธ ๋ฐ˜ํ™˜) ๋˜๋Š” sysret(ํ˜„๋Œ€ syscall ๋ฐ˜ํ™˜) ๋ช…๋ น์ด trap frame์„ ๊บผ๋‚ด RIPยทRSPยทRFLAGSยทCS๋ฅผ ์‚ฌ์šฉ์ž ๊ฐ’์œผ๋กœ ๋ณต์›ํ•˜๋ฉด์„œ ๊ถŒํ•œ๋„ 3(์‚ฌ์šฉ์ž)์œผ๋กœ ๋‚ด๋ฆฝ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
์‚ฌ์šฉ์ž ๋ชจ๋“œ ์ฝ”๋“œ ์‹คํ–‰
  โ†“ โ‘  syscall / int 0x80 (์‹œ์Šคํ…œ ์ฝœ)
  โ†“ โ‘ก ์™ธ๋ถ€ ์žฅ์น˜ ์ธํ„ฐ๋ŸฝํŠธ
  โ†“ โ‘ข Page FaultยทDivide by Zero (์˜ˆ์™ธ)
  โ†“ โ‘ฃ int 3 (๋””๋ฒ„๊ฑฐ)
CPU: trap frame ์ €์žฅ โ†’ CS.RPL = 0 โ†’ IDT ํ•ธ๋“ค๋Ÿฌ๋กœ ์ ํ”„
  โ†“
์ปค๋„ ๋ชจ๋“œ ์ฝ”๋“œ ์‹คํ–‰
  โ†“ iret / sysret
CPU: trap frame ๋ณต์› โ†’ CS.RPL = 3
์‚ฌ์šฉ์ž ๋ชจ๋“œ ์ฝ”๋“œ ์žฌ๊ฐœ

๋ชจ๋“œ ์Šค์œ„์น˜๋งŒ ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ

1
2
3
// ์‹œ์Šคํ…œ ์ฝœ์ด ์ฆ‰์‹œ ๋๋‚จ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ
DWORD pid = GetCurrentProcessId();   // user โ†’ kernel โ†’ user, ๊ฐ™์€ ์Šค๋ ˆ๋“œ
QueryPerformanceCounter(&counter);    // ๊ฐ™์€ ์Šค๋ ˆ๋“œ, ๊ฐ™์€ quantum ์•ˆ์—์„œ ๋ณต๊ท€

์œ„ ํ˜ธ์ถœ๋“ค์€ user mode โ†’ kernel mode ์ „ํ™˜์ด ์ผ์–ด๋‚˜์ง€๋งŒ(๋ชจ๋“œ ์Šค์œ„์น˜), ์ •๋ณด๋ฅผ ์ฝ๊ณ  ์ฆ‰์‹œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋Œ์•„์˜ค๋ฏ€๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ๊ฐˆ์•„๋ผ์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ).

์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ

ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๊ฐ€ ์ผ์–ด๋‚˜๋ ค๋ฉด ๋จผ์ € ์‚ฌ์šฉ์ž ๋ชจ๋“œ โ†’ ์ปค๋„ ๋ชจ๋“œ (๋ชจ๋“œ ์Šค์œ„์น˜)๊ฐ€ ์ผ์–ด๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ํ•ญ์ƒ ์ปค๋„ ๋ชจ๋“œ์—์„œ ์‹คํ–‰๋˜๋‹ˆ๊นŒ์š”. ๊ทธ ํ•ธ๋“ค๋Ÿฌ ์•ˆ์—์„œ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋ฅผ ๊ณจ๋ผ ๊ทธ ์Šค๋ ˆ๋“œ์˜ ์ปจํ…์ŠคํŠธ๋กœ ๋ณต์›ํ•œ ๋’ค ๋‹ค์‹œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ (๋˜ ํ•œ ๋ฒˆ์˜ ๋ชจ๋“œ ์Šค์œ„์น˜)๋กœ ๋ณต๊ท€ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
์‚ฌ์šฉ์ž ์ฝ”๋“œ ์‹คํ–‰ ์ค‘ (user mode)
  โ†“ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ
๋ชจ๋“œ ์Šค์œ„์น˜: user โ†’ kernel
  โ†“
์Šค์ผ€์ค„๋Ÿฌ ์ง„์ž… โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ (์Šค๋ ˆ๋“œ A โ†’ ์Šค๋ ˆ๋“œ B)
  โ†“
๋ชจ๋“œ ์Šค์œ„์น˜: kernel โ†’ user
์‚ฌ์šฉ์ž ์ฝ”๋“œ ์‹คํ–‰ (์Šค๋ ˆ๋“œ B์˜ user mode)

Fiber๋Š” ๋‘˜ ๋‹ค ์—†์Œ

Fiber API(SwitchToFiber)๋Š” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์ง์ ‘ SPยทPC๋ฅผ ๋ฐ”๊ฟ”์น˜๊ธฐํ•˜๋ฏ€๋กœ ๋ชจ๋“œ ์Šค์œ„์น˜๋„ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜(OS ๊ด€์ )๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. OS ์Šค๋ ˆ๋“œ๋Š” ๊ทธ๋Œ€๋กœ์ด๊ณ , ๊ทธ ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์‚ฌ์šฉ์ž ์ฝ”๋“œ๊ฐ€ ์ž๊ธฐ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋งŒ ๊ฐˆ์•„์น˜์šฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ˆ˜์‹ญ nanosecond์— ๋๋‚ฉ๋‹ˆ๋‹ค.

ํ•œ ์ค„ ์š”์•ฝ

๋ชจ๋“œ ์Šค์œ„์น˜๋Š” ๊ถŒํ•œ์ด ๋ฐ”๋€Œ๋Š” ๊ฒƒ, ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ์‹คํ–‰ ์ฃผ์ฒด๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ. ๋‘˜์€ ์ž์ฃผ ํ•จ๊ป˜ ์ผ์–ด๋‚˜์ง€๋งŒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


6. ๋น„์šฉ ์š”์†Œ โ€” ์บ์‹œ flush ยท TLB flush ยท ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€

๋น„์šฉ์€ ๊ธ€๋จธ๋ฆฌํ‘œ๋กœ ๋ถ„๋ฆฌํ•ด ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค(20๋ฒˆ ํŒŒ์ผ์—์„œ ํ™•์ธ๋œ ์‚ฌ์šฉ์ž ์„ ํ˜ธ ๊ทธ๋Œ€๋กœ).

๋น„์šฉ ์š”์†Œ 1 โ€” ๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์› (์ง์ ‘ ๋น„์šฉ)

๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ(TCB)์— ์˜ฎ๊ธฐ๋Š” ์ง์ ‘์  ์ž‘์—…์ž…๋‹ˆ๋‹ค. x86_64์˜ GPR 16๊ฐœ + ํ”Œ๋ž˜๊ทธ + ์„ธ๊ทธ๋จผํŠธ + (์„ ํƒ์ ) FPU/SIMD๋ฅผ ํ•ฉ์น˜๋ฉด ํ•œ ๋ฒˆ์— ์ˆ˜๋ฐฑ ๋ฐ”์ดํŠธ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ๋กœ ๋ณด๋‚ด๊ณ , ๋‹ค์‹œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

  • ๋ณดํ†ต ์ˆ˜๋ฐฑ nanosecond ์ˆ˜์ค€
  • ๊ทธ ์ž์ฒด๋กœ๋Š” ์ž‘์ง€๋งŒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋งค quantum(์˜ˆ: 15.6ms)๋งˆ๋‹ค ์ผ์–ด๋‚˜๋ฉด ๋ˆ„์ ๋จ
  • AVX-512 ํ™œ์„ฑํ™” ์‹œ ZMM 32ร—64B = 2KB๋ผ ์ง์ ‘ ๋น„์šฉ์ด ๋Š˜์–ด๋‚จ

๋น„์šฉ ์š”์†Œ 2 โ€” ์บ์‹œ ์ฝœ๋“œ (Cache Cold) โ€” ๊ฐ€์žฅ ํฐ ๊ฐ„์ ‘ ๋น„์šฉ

์ƒˆ๋กœ ๋“ค์–ด์˜จ ์Šค๋ ˆ๋“œ B์˜ ๋ฐ์ดํ„ฐยท๋ช…๋ น์–ด๊ฐ€ L1ยทL2 ์บ์‹œ์— ์—†์œผ๋ฏ€๋กœ, ์ง„์ž… ์งํ›„ ์ค„์ค„์ด ์บ์‹œ ๋ฏธ์Šค(cache miss) ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์บ์‹œ ๋ผ์ธ(๋ณดํ†ต 64B)์„ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ํ•œ ๋ฒˆ์— ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ nanosecond๊ฐ€ ๋“ค๊ณ , ์ด๊ฒŒ ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๋ฒˆ ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
์Šค๋ ˆ๋“œ A ์‹คํ–‰ ์ค‘ โ†’ A์˜ working set์ด L1/L2์— ์บ์‹ฑ๋จ
  โ†“ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
์Šค๋ ˆ๋“œ B ์‹คํ–‰ ์‹œ์ž‘ โ†’ A์˜ ์บ์‹œ ๋ผ์ธ์ด ๊ฐ€๋“, B์˜ ๋ฐ์ดํ„ฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ์—
  โ†“
B์˜ ๋ช…๋ น ์‹คํ–‰ โ†’ L1 miss โ†’ L2 miss โ†’ L3 miss โ†’ DRAM ์ ‘๊ทผ (~100ns)
              โ†’ ์บ์‹œ ๋ผ์ธ ๊ฐ€์ ธ์˜ค๊ธฐ โ†’ ๋‹ค์Œ ๋ช…๋ น ์‹คํ–‰ โ†’ ๋˜ ๋‹ค๋ฅธ ๋ฏธ์Šค โ†’ ...
  • ์ง์ ‘ ๋น„์šฉ๋ณด๋‹ค ์ˆ˜~์ˆ˜์‹ญ ๋ฐฐ ํฐ ๊ฒฝ์šฐ๊ฐ€ ์ผ๋ฐ˜์ 
  • ์ž„๊ณ„ ๊ตฌ์—ญ์ด ์งง์œผ๋ฉด spin lock์ด mutex๋ณด๋‹ค ๋น ๋ฅธ ํ•ต์‹ฌ ์ด์œ 
  • L1 ์บ์‹œ ํฌ๊ธฐ(๋ณดํ†ต 32~64KB), L2(512KB~1MB)๊ฐ€ ์ž‘์•„ ๋นจ๋ฆฌ ์ฑ„์›Œ์ง

๋น„์šฉ ์š”์†Œ 3 โ€” TLB Flush (ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์—์„œ๋งŒ)

TLB(Translation Lookaside Buffer, ์ฃผ์†Œ ๋ณ€ํ™˜ ์บ์‹œ)๋Š” ๊ฐ€์ƒ ์ฃผ์†Œ โ†’ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋งคํ•‘์„ ์บ์‹ฑํ•˜๋Š” MMU(Memory Management Unit) ๋‚ด๋ถ€ ์บ์‹œ์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต 64~512 ์—”ํŠธ๋ฆฌ๋กœ ์ž‘์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์ด ๋‹ค๋ฅด๋ฏ€๋กœ ์ด ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
๊ฐ€์ƒ ์ฃผ์†Œ 0x12345678 (ํ”„๋กœ์„ธ์Šค P1) โ†’ ๋ฌผ๋ฆฌ ์ฃผ์†Œ 0xAAAA  โ† TLB ์บ์‹ฑ
                                                          โ†“ ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ (P1 โ†’ P2)
๊ฐ€์ƒ ์ฃผ์†Œ 0x12345678 (ํ”„๋กœ์„ธ์Šค P2) โ†’ ๋ฌผ๋ฆฌ ์ฃผ์†Œ 0xBBBB  โ† ๋‹ค๋ฅธ ๋งคํ•‘!
                                                          โ†’ ๊ธฐ์กด TLB ์—”ํŠธ๋ฆฌ๋Š” ๋ฌดํšจํ™” ํ•„์š”
  • TLB flush ํ›„์—” ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ(page table walk) ๋ถ€ํ„ฐ ์‹œ์ž‘
  • 4๋‹จ๊ณ„ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์ด๋ฉด ํ•œ ๋ฒˆ ์›Œํฌ์— 4๋ฒˆ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ
  • ํ˜„๋Œ€ x86์€ PCID(Process Context ID) ๋กœ TLB ์—”ํŠธ๋ฆฌ์— ํ”„๋กœ์„ธ์Šค ID๋ฅผ ํƒœ๊น…ํ•ด ์ „์ฒด flush๋ฅผ ํšŒํ”ผ
  • ARM์€ ASID(Address Space ID) ๋กœ ๊ฐ™์€ ์—ญํ• 
  • ์Šค๋ ˆ๋“œ ์ „ํ™˜์—์„  ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋ผ TLB flush ์—†์Œ โ€” ์ด๊ฒŒ 5~10๋ฐฐ ์ฐจ์ด์˜ ํ•ต์‹ฌ

๋น„์šฉ ์š”์†Œ 4 โ€” ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€์™€ ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ ๋ฌดํšจํ™”

CPU์˜ instruction pipeline์— ๋“ค์–ด ์žˆ๋˜ ๋ช…๋ น๋“ค์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์‹œ์ ์— ๋ชจ๋‘ ํ๊ธฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ(branch predictor)๊ฐ€ ํ•™์Šตํ•ด ๋‘” ํŒจํ„ด์ด ์ด์ „ ์Šค๋ ˆ๋“œ ์ฝ”๋“œ ๊ธฐ์ค€์ด๋ผ, ์ƒˆ ์Šค๋ ˆ๋“œ์˜ ๋ถ„๊ธฐ ํŒจํ„ด๊ณผ ์–ด๊ธ‹๋‚˜ ์ž ์‹œ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

  • Pipeline drain: ๋ณดํ†ต ์‹ญ์ˆ˜ cycles
  • BTB(Branch Target Buffer) ์ฝœ๋“œ: ๋ถ„๊ธฐ๋งˆ๋‹ค misprediction โ†’ flush ๋ฐ˜๋ณต

๋น„์šฉ ์š”์†Œ 5 โ€” ์ปค๋„ ์ง„์ž…(๋ชจ๋“œ ์Šค์œ„์น˜) ์ž์ฒด ๋น„์šฉ

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ๊ฑฐ์˜ ํ•ญ์ƒ ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ ์ผ์–ด๋‚˜๋ฏ€๋กœ ๊ทธ ๋น„์šฉ์ด ํ•จ๊ป˜ ๋“ญ๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์ฝœ ํ•œ ๋ฒˆ์— ๋ณดํ†ต 100~500 nanosecond, Spectre/Meltdown ์™„ํ™” ํŒจ์น˜ ์ดํ›„์—๋Š” KPTI(Kernel Page Table Isolation) ๋•Œ๋ฌธ์— ๋” ๋น„์‹ธ์กŒ์Šต๋‹ˆ๋‹ค(์ˆ˜ microsecond๊นŒ์ง€).

๋น„์šฉ ์š”์†Œ ์ข…ํ•ฉ

์š”์†Œ์ง์ ‘/๊ฐ„์ ‘ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์Šค๋ ˆ๋“œ ์ „ํ™˜์ ˆ๋Œ€ ๋น„์šฉ
๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์›์ง์ ‘OO์ˆ˜๋ฐฑ ns
๋ชจ๋“œ ์Šค์œ„์น˜ (์ปค๋„ ์ง„์ž…)์ง์ ‘OO100~500 ns (KPTI ์‹œ ๋” ๋น„์Œˆ)
์บ์‹œ ์ฝœ๋“œ๊ฐ„์ ‘O (ํผ)O (์ž‘์Œ)์ˆ˜~์ˆ˜์‹ญ ฮผs
TLB flush / ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ๊ฐ„์ ‘OX์ˆ˜ ฮผs
ํŒŒ์ดํ”„๋ผ์ธยท๋ถ„๊ธฐ ์˜ˆ์ธก๊ฐ„์ ‘OO์ˆ˜์‹ญ ns~์ˆ˜๋ฐฑ ns

์ดํ•ฉ: ์Šค๋ ˆ๋“œ ์ „ํ™˜ ์•ฝ 1~5ฮผs, ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ์•ฝ 5~20ฮผs (์›Œํฌ๋กœ๋“œยทCPU์— ๋”ฐ๋ผ ๋ณ€๋™).


7. ํ”„๋กœ์„ธ์Šค vs ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๋น„์šฉ ๋น„๊ต

19๋ฒˆ์—์„œ ๋‹ค๋ฃฌ ๋น„๊ต๋ฅผ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ ๊ด€์ ์—์„œ ์ •๋ฐ€ํ•˜๊ฒŒ ๋‹ค์‹œ ๋ด…๋‹ˆ๋‹ค.

๋น„๊ต ํ‘œ

๋น„์šฉ ํ•ญ๋ชฉํ”„๋กœ์„ธ์Šค ์ „ํ™˜์Šค๋ ˆ๋“œ ์ „ํ™˜ (๊ฐ™์€ ํ”„๋กœ์„ธ์Šค)
๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์›OO
ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค (cr3) ๊ต์ฒดOX
TLB flush (PCID ์—†์„ ์‹œ)OX
L1/L2 ์บ์‹œ ์ฝœ๋“œํผ (working set ์™„์ „ ๊ต์ฒด)๋ณดํ†ต (์Šค๋ ˆ๋“œ๋ณ„ working set ์ •๋„)
L1 i-cache ์ฝœ๋“œํผ๋ณดํ†ต (์ฝ”๋“œ ์ผ๋ถ€ ๊ณต์œ )
ํ•ธ๋“ค ํ…Œ์ด๋ธ” ๊ต์ฒดOX
๋ณด์•ˆ ํ† ํฐ ๊ต์ฒดOX
๋ชจ๋“œ ์Šค์œ„์น˜ ์ž์ฒดOO
์ด ๋น„์šฉ (๋Œ€๋žต)5~20 ฮผs1~5 ฮผs
์ƒ๋Œ€ ๋น„์šฉ5~10๋ฐฐ๊ธฐ์ค€

์บ์‹œ ์ฝœ๋“œ์˜ ์ฐจ์ด๊ฐ€ ๋ฏธ๋ฌ˜ํ•œ ์ด์œ 

๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ์Šค๋ ˆ๋“œ๋“ค๋„ working set์ด ๋‹ค๋ฅด๋ฉด ์บ์‹œ ์ฝœ๋“œ ๋น„์šฉ์ด ํฝ๋‹ˆ๋‹ค โ€” ์˜ˆ๋ฅผ ๋“ค์–ด ์Šค๋ ˆ๋“œ A๊ฐ€ ๋ถ€๋ถ„ ํŠธ๋ฆฌ X๋ฅผ ์ž‘์—…ํ•˜๊ณ , ์Šค๋ ˆ๋“œ B๊ฐ€ ๋ถ€๋ถ„ ํŠธ๋ฆฌ Y๋ฅผ ์ž‘์—…ํ•˜๋ฉด ๋‘˜ ๋‹ค ์ž๊ธฐ ๋ฐ์ดํ„ฐ๋กœ ์บ์‹œ๋ฅผ ์ฑ„์›Œ๋‘ก๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ์ฝ”๋“œ ์˜์—ญ(.text ์„น์…˜)์€ ๊ณต์œ ๋˜๋ฏ€๋กœ i-cache ์ฝœ๋“œ๋Š” ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋ณด๋‹ค ์ž‘์Šต๋‹ˆ๋‹ค. ๋˜ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋ผ ๊ฐ€์ƒ ์ฃผ์†Œ๊ฐ€ ๊ฐ™์•„ TLB ์—”ํŠธ๋ฆฌ๋„ ์ผ๋ถ€ ์žฌ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

PCID/ASID๋กœ ์ขํ˜€์ง„ ๊ฒฉ์ฐจ

ํ˜„๋Œ€ x86(Haswell+)๊ณผ ARMv8์€ TLB ์—”ํŠธ๋ฆฌ์— ํ”„๋กœ์„ธ์Šค ID๋ฅผ ํƒœ๊น…ํ•ด ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ์‹œ ์ „์ฒด flush๋ฅผ ํšŒํ”ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ PCID๊ฐ€ ํ™œ์„ฑํ™”๋œ ์‹œ์Šคํ…œ์—์„  ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ๋น„์šฉ์ด ์˜ˆ์ „๋ณด๋‹ค ์ค„์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์บ์‹œ ์ฝœ๋“œ๋Š” PCID๋กœ๋„ ํšŒํ”ผ ๋ชป ํ•จ โ€” TLB๋Š” ๋งคํ•‘ ์ •๋ณด ์บ์‹œ๊ณ , ์บ์‹œ๋Š” ๋ฐ์ดํ„ฐ ์บ์‹œ๋ผ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์‹ค๋ฌด ๊ฒฐ์ •

1
2
3
4
5
6
7
8
60fps ๊ฒŒ์ž„ ์—”์ง„ (ํ”„๋ ˆ์ž„๋‹น 16.6ms):
  โ†’ ํ•œ ๋ฒˆ์— ์ˆ˜๋งŒ ๊ฐ์ฒด ๋™๊ธฐํ™”
  โ†’ ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ๋น„์šฉ์„ ๊ฒฌ๋”œ ์ˆ˜ ์—†์Œ
  โ†’ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ + ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ๊ฒŒ์ž„/๋ Œ๋” ์Šค๋ ˆ๋“œ ๋ถ„๋ฆฌ

Chrome ํƒญ (๋ณด์•ˆ ๊ฒฉ๋ฆฌ ์šฐ์„ ):
  โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ๋ณด๋‹ค ๊ฒฉ๋ฆฌ๊ฐ€ ์ค‘์š”
  โ†’ ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค ์ฑ„ํƒ, IPC ๋น„์šฉ ๊ฐ์ˆ˜

19๋ฒˆ์˜ ๊ฒฐ๋ก ์„ ๊ทธ๋Œ€๋กœ ์ด์–ด๋ฐ›์Šต๋‹ˆ๋‹ค โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์€ ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค vs ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์„ ํƒ์˜ ํ•ต์‹ฌ ๋ณ€์ˆ˜ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.


8. ์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ์˜ ์—ฐ๊ด€ โ€” ์„ ์ ํ˜•/๋น„์„ ์ ํ˜•/RR/์šฐ์„ ์ˆœ์œ„

์„ ์ ํ˜• vs ๋น„์„ ์ ํ˜•

ํ•ญ๋ชฉ์„ ์ ํ˜• (Preemptive)๋น„์„ ์ ํ˜• / ํ˜‘๋ ฅ์  (Cooperative)
์Šค์œ„์นญ ํŠธ๋ฆฌ๊ฑฐํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ๊ฐ•์ œ์Šค๋ ˆ๋“œ์˜ ์ž๋ฐœ์  ์–‘๋ณด
์‘๋‹ต์„ฑ์ข‹์Œ (๋ณด์žฅ ๊ฐ€๋Šฅ)๋‚˜์จ (ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์–‘๋ณด ์•ˆ ํ•˜๋ฉด ๋ฉˆ์ถค)
์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋นˆ๋„๋†’์Œ (quantum๋งˆ๋‹ค)๋‚ฎ์Œ (์–‘๋ณดํ•  ๋•Œ๋งŒ)
์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ๋†’์Œ (๋ˆ„์ )๋‚ฎ์Œ
์‚ฌ๋ก€WindowsยทLinuxยทmacOSWindows 3.1ยท์˜ˆ์ „ macOSยทFiberยท์ฝ”๋ฃจํ‹ด

Round-Robin (RR)

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ์„ ์ ํ˜• ์Šค์ผ€์ค„๋ง์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  Ready ์Šค๋ ˆ๋“œ์— ๊ฐ™์€ time slice(quantum)๋ฅผ ๋Œ๋ฆฌ๋ฉฐ ์ˆœํ™˜ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
Ready ํ: [A, B, C, D]
quantum ๋งŒ๋ฃŒ โ†’ A๋Š” ํ ๋์œผ๋กœ โ†’ ๋‹ค์Œ์€ B
quantum ๋งŒ๋ฃŒ โ†’ B๋Š” ํ ๋์œผ๋กœ โ†’ ๋‹ค์Œ์€ C
...

์žฅ์ ์€ ๊ณต์ •์„ฑ๊ณผ ๋‹จ์ˆœํ•จ, ๋‹จ์ ์€ ์šฐ์„ ์ˆœ์œ„ ๋ฌด์‹œยท์งง์€ ์ž‘์—…๊ณผ ๊ธด ์ž‘์—…์˜ ๋™๋“ฑ ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค.

์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง

Ready ํ๋ฅผ ์šฐ์„ ์ˆœ์œ„๋ณ„๋กœ ๋‚˜๋ˆ„๊ณ , ํ•ญ์ƒ ๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„ ํ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋จผ์ € ๋””์ŠคํŒจ์น˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์žฅ์ : ์ค‘์š”ํ•œ ์ž‘์—…(์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒยท์‹ค์‹œ๊ฐ„) ๋ณด์žฅ
  • ๋‹จ์ : ๊ธฐ์•„(starvation) โ€” ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„ ์Šค๋ ˆ๋“œ๊ฐ€ ์˜์›ํžˆ ๋ชป ๋Œ ์ˆ˜ ์žˆ์Œ
  • ํ•ด๊ฒฐ์ฑ…: ์šฐ์„ ์ˆœ์œ„ ๋ถ€์ŠคํŒ…(priority boost) โ€” Windows๋Š” ์˜ค๋ž˜ ๊ธฐ๋‹ค๋ฆฐ ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ์˜ฌ๋ฆผ

Windows๋Š” ์šฐ์„ ์ˆœ์œ„ 0~31์„ ์“ฐ๊ณ (0~15: dynamic, 16~31: real-time), I/O ์™„๋ฃŒยทUI ์ด๋ฒคํŠธ ์‹œ ๋ถ€์ŠคํŒ…์œผ๋กœ ์‘๋‹ต์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

MLFQ (Multi-Level Feedback Queue)

์—ฌ๋Ÿฌ ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ๋‘๊ณ , ์Šค๋ ˆ๋“œ์˜ ํ–‰๋™ ํŒจํ„ด์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ํ ์‚ฌ์ด๋ฅผ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
ํ 1 (๋†’์€ ์šฐ์„ ์ˆœ์œ„, ์งง์€ quantum)
ํ 2 (์ค‘๊ฐ„ ์šฐ์„ ์ˆœ์œ„, ์ค‘๊ฐ„ quantum)
ํ 3 (๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„, ๊ธด quantum)

์ƒˆ ์Šค๋ ˆ๋“œ โ†’ ํ 1 (์งง์€ quantum, ์‘๋‹ต์„ฑ ์šฐ์„ )
quantum ๋‹ค ์“ฐ๊ณ ๋„ ์•ˆ ๋๋‚จ โ†’ ํ 2๋กœ ๊ฐ•๋“ฑ (CPU-bound ์˜์‹ฌ)
quantum ๋‹ค ์“ฐ๊ณ ๋„ ์•ˆ ๋๋‚จ โ†’ ํ 3๋กœ ๊ฐ•๋“ฑ
I/O ๋Œ€๊ธฐ๋กœ ์–‘๋ณด โ†’ ๋‹ค์‹œ ํ 1๋กœ ์Šน๊ฒฉ (์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ๋กœ ์žฌ๋ถ„๋ฅ˜)

์ด๊ฒŒ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์ž‘์—…๊ณผ ๋ฐฐ์น˜ ์ž‘์—…์„ ์ž๋™์œผ๋กœ ๋ถ„๋ฅ˜ํ•ฉ๋‹ˆ๋‹ค. Windows์˜ dynamic ์šฐ์„ ์ˆœ์œ„, Linux์˜ CFS(Completely Fair Scheduler) ๊ฐ™์€ ํ˜„๋Œ€ ์Šค์ผ€์ค„๋Ÿฌ๋“ค์˜ ์„ ์กฐ์ž…๋‹ˆ๋‹ค.

time slice (quantum) ๊ธธ์ด์˜ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„

quantum ๊ธธ์ด์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋นˆ๋„์‘๋‹ต์„ฑthroughput
์งง์Œ (1ms)๋†’์Œ์ข‹์Œ๋‚˜์จ (์˜ค๋ฒ„ํ—ค๋“œ ๋ˆ„์ )
๋ณดํ†ต (10~20ms)๋ณดํ†ต๋ณดํ†ต๋ณดํ†ต
๊ธบ (100ms+)๋‚ฎ์Œ๋‚˜์จ (๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ฆ๊ฐ€)์ข‹์Œ

Windows ๊ธฐ๋ณธ quantum์€ ์•ฝ 15.6ms(10ms๋„ ๊ฐ€๋Šฅ, ๋ฉ€ํ‹ฐ๋ฏธ๋””์–ด ํƒ€์ด๋จธ๋กœ 1ms๊นŒ์ง€ ๋‹จ์ถ• ๊ฐ€๋Šฅ), Linux CFS๋Š” ๋™์ ์œผ๋กœ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค(๋ณดํ†ต 4ms ์ดํ•˜). ๊ฒŒ์ž„์ด๋‚˜ ๋ฉ€ํ‹ฐ๋ฏธ๋””์–ด ์•ฑ์€ timeBeginPeriod(1)๋กœ quantum์„ ์ค„์—ฌ ์‘๋‹ต์„ฑ์„ ํ™•๋ณดํ•˜์ง€๋งŒ, ์ด๋Š” ์‹œ์Šคํ…œ ์ „์ฒด์— ์˜ํ–ฅ์„ ์ฃผ๋ฏ€๋กœ ์‹ ์ค‘ํžˆ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋…ธํŠธ๋ถ ๋ฐฐํ„ฐ๋ฆฌ ์ˆ˜๋ช… ๋‹จ์ถ• ๋“ฑ).

CPU Affinity์™€ NUMA

์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค์Œ ์Šค๋ ˆ๋“œ๋ฅผ ๊ณ ๋ฅผ ๋•Œ, ๊ทธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋งˆ์ง€๋ง‰์— ์‹คํ–‰๋๋˜ ์ฝ”์–ด์™€ ๊ฐ™์€ ์ฝ”์–ด์— ๋ฐฐ์น˜ํ•˜๋ฉด L1/L2 ์บ์‹œ๊ฐ€ ์ผ๋ถ€ ์‚ด์•„ ์žˆ์–ด ์บ์‹œ ์ฝœ๋“œ ๋น„์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ CPU affinity ์ตœ์ ํ™”์ž…๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ ์†Œ์ผ“ NUMA(Non-Uniform Memory Access) ์‹œ์Šคํ…œ์—์„  ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์‹œ๊ฐ„์ด ๋…ธ๋“œ๋ณ„๋กœ ๋‹ฌ๋ผ์„œ, ์Šค๋ ˆ๋“œ๋ฅผ ์ž๊ธฐ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์žˆ๋Š” NUMA ๋…ธ๋“œ์— ๋ฌถ์–ด๋‘๋Š” ๊ฒŒ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. Windows๋Š” SetThreadAffinityMask/SetThreadIdealProcessor, Linux๋Š” sched_setaffinity๋กœ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.


9. Windows ๊ด€์  โ€” Win32 ์Šค๋ ˆ๋“œ API์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ

์—ฌ๊ธฐ๋ถ€ํ„ฐ๋Š” MSVC ๋ฌธ์„œ ํŠธ๋ฆฌ(learn.microsoft.com/ko-kr/cpp/)๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉฐ Windows์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๋‹จ๊ณ„๋ณ„๋กœ ๋ด…๋‹ˆ๋‹ค.

9.1 CreateThread โ€” ๊ฐ€์žฅ ๊ธฐ๋ณธ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>

DWORD WINAPI WorkerProc(LPVOID lpParam) {
    DWORD id = GetCurrentThreadId();
    // ... ์ž‘์—… ...
    return 0;
}

int main() {
    HANDLE hThread = CreateThread(
        NULL,           // ๊ธฐ๋ณธ ๋ณด์•ˆ
        0,              // ๊ธฐ๋ณธ ์Šคํƒ ํฌ๊ธฐ (1MB)
        WorkerProc,     // ์‹œ์ž‘ ํ•จ์ˆ˜
        NULL,           // ์ธ์ž
        0,              // ์ฆ‰์‹œ ์‹คํ–‰ (CREATE_SUSPENDED ์•ˆ ์คŒ)
        NULL            // ThreadId ์ถœ๋ ฅ (NULL์ด๋ฉด ๋ฌด์‹œ)
    );

    WaitForSingleObject(hThread, INFINITE);  // ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ ๋Œ€๊ธฐ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
    CloseHandle(hThread);
    return 0;
}

CreateThread๋Š” OS ์ปค๋„์— ์ƒˆ TCB๋ฅผ ๋งŒ๋“ค๊ณ  Ready ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ์ฆ‰์‹œ ์‹คํ–‰ํ• ์ง€(0) ์ผ์‹œ์ •์ง€ ์ƒํƒœ๋กœ ๋งŒ๋“ค์ง€(CREATE_SUSPENDED)๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. _beginthreadex ๋Š” CRT ์ดˆ๊ธฐํ™”๋ฅผ ํ•จ๊ป˜ ํ•ด์ฃผ๋Š” ๋ž˜ํผ๋ผ C ๋Ÿฐํƒ€์ž„์„ ์“ฐ๋Š” ์ฝ”๋“œ๋Š” ์ด์ชฝ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค(stdioยทerrnoยทstrtok ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ TLS๋ฅผ ์“ฐ๊ธฐ ๋•Œ๋ฌธ).

9.2 SwitchToThread / Sleep(0) โ€” ์ž๋ฐœ์  ์–‘๋ณด

1
2
3
4
5
6
7
8
9
10
// ๊ฐ™์€ ์ฝ”์–ด์˜ ๋‹ค๋ฅธ Ready ์Šค๋ ˆ๋“œ์— ์–‘๋ณด
BOOL switched = SwitchToThread();
// switched == TRUE: ์‹ค์ œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋์Œ
// switched == FALSE: ์–‘๋ณดํ•  ์Šค๋ ˆ๋“œ๊ฐ€ ์—†์–ด ์ฆ‰์‹œ ๋ณต๊ท€

// ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ์Šค๋ ˆ๋“œ์— ์–‘๋ณด (์—†์œผ๋ฉด ๊ทธ๋ƒฅ 0ms ๋Œ€๊ธฐ ํ›„ ๋ณต๊ท€)
Sleep(0);

// 1ms ๋Œ€๊ธฐ (์‹ค์ œ๋ก  quantum ๋‹จ์œ„๋กœ ๋ฐ˜์˜ฌ๋ฆผ โ€” ๋ณดํ†ต 15.6ms)
Sleep(1);

์ฐจ์ด๋ฅผ ๋ช…ํ™•ํžˆ ์ •๋ฆฌํ•˜๋ฉด:

ํ˜ธ์ถœ์–‘๋ณด ๋Œ€์ƒ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๊ถŒ์žฅ ์‚ฌ์šฉ์ฒ˜
Sleep(0)๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ์Šค๋ ˆ๋“œํ›„๋ณด ์žˆ์„ ๋•Œ๋งŒ์šฐ์„ ์ˆœ์œ„ ๊ท ๋“ฑ spin loop
SwitchToThread๊ฐ™์€ ์ฝ”์–ด์˜ ๋ชจ๋“  Ready ์Šค๋ ˆ๋“œํ›„๋ณด ์žˆ์„ ๋•Œ๋งŒspin lock์˜ ์–‘๋ณด ๋‹จ๊ณ„
Sleep(1+)๋ชจ๋“  ํ›„๋ณด (์ง€์ • ์‹œ๊ฐ„ ํ›„ ๊นธ)ํ•ญ์ƒ์ง„์งœ ๋Œ€๊ธฐ
_mm_pause์–‘๋ณด ์•ˆ ํ•จ์—†์Œ์งง์€ spin (CPU ํžŒํŠธ๋งŒ)

spin lock ๊ตฌํ˜„์—์„œ ํ”ํ•œ ํŒจํ„ด์€:

1
2
3
4
while (!try_lock()) {
    for (int i = 0; i < 16; ++i) _mm_pause();  // CPU์— spin ํžŒํŠธ (์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ)
    if (!try_lock()) SwitchToThread();          // ๊ทธ๋ž˜๋„ ๋ชป ์žก์œผ๋ฉด ์–‘๋ณด
}

9.3 WaitForSingleObject / WaitForMultipleObjects โ€” ๋ธ”๋กœํ‚น

1
2
3
4
5
6
7
8
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);  // auto-reset event

// ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ SetEvent(hEvent) ํ•  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
DWORD result = WaitForSingleObject(hEvent, INFINITE);

// ์—ฌ๋Ÿฌ ๊ฐ์ฒด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‹œ๊ทธ๋„๋  ๋•Œ๊นŒ์ง€
HANDLE handles[] = { hEvent1, hEvent2, hMutex };
DWORD which = WaitForMultipleObjects(3, handles, FALSE, INFINITE);

WaitForSingleObject๋Š” ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด๊ฐ€ ์ด๋ฏธ ์‹œ๊ทธ๋„ ์ƒํƒœ๋ฉด ์ฆ‰์‹œ ๋ณต๊ท€(์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ), ์•„๋‹ˆ๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ Wait ์ƒํƒœ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ธ์ž INFINITE๋Š” ์‹œ๊ฐ„ ์ œํ•œ ์—†์Œ, 0์€ ์ฆ‰์‹œ ํด๋ง(ํฌ๊ธฐ), 0 < n ์€ n ๋ฐ€๋ฆฌ์ดˆ ๋Œ€๊ธฐ.

9.4 SuspendThread / ResumeThread โ€” ๊ฐ•์ œ ์ผ์‹œ์ •์ง€

1
2
DWORD prev = SuspendThread(hThread);   // ์นด์šดํ„ฐ ์ฆ๊ฐ€, 0๋ณด๋‹ค ํฌ๋ฉด ์ผ์‹œ์ •์ง€ ์ƒํƒœ
ResumeThread(hThread);                  // ์นด์šดํ„ฐ ๊ฐ์†Œ, 0๋˜๋ฉด ์žฌ๊ฐœ

์Šค๋ ˆ๋“œ๋ฅผ ์™ธ๋ถ€์—์„œ ๊ฐ•์ œ๋กœ ์ผ์‹œ์ •์ง€/์žฌ๊ฐœํ•˜๋Š” ํ˜ธ์ถœ์ž…๋‹ˆ๋‹ค. ๋””๋ฒ„๊ฑฐ(SuspendThread๋กœ ๋ฉˆ์ถฐ์„œ ์ฝœ์Šคํƒ ๊ฒ€์‚ฌ), ํ”„๋กœํŒŒ์ผ๋Ÿฌ(์ƒ˜ํ”Œ๋ง ์‹œ ์ž ๊น ๋ฉˆ์ถค), ์ผ๋ถ€ ์ œ์–ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋งŒ ์”๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ฝ”๋“œ์—์„œ ๋™๊ธฐํ™” ๋ชฉ์ ์œผ๋กœ ์“ฐ๋ฉด ์•ˆ ๋จ โ€” ๋ฝ์„ ๋“ค๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋ฉˆ์ถ”๋ฉด ๋ฐ๋“œ๋ฝ์ด ๋ฉ๋‹ˆ๋‹ค.

9.5 ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ๊ณผ์˜ ๊ด€๊ณ„ ์ •๋ฆฌ

1
2
3
4
5
6
CreateThread       โ†’ ์ƒˆ TCB ์ƒ์„ฑ โ†’ Ready ํ ์ง„์ž… โ†’ ์Šค์ผ€์ค„๋Ÿฌ ๋””์ŠคํŒจ์น˜ ์‹œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
SwitchToThread     โ†’ ์ฆ‰์‹œ ์–‘๋ณด โ†’ ํ›„๋ณด ์žˆ์œผ๋ฉด ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
Sleep(0)           โ†’ ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„ ์–‘๋ณด
Sleep(n>0)         โ†’ ํ•ญ์ƒ Wait ์ƒํƒœ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
WaitForSingleObject โ†’ ๊ฐ์ฒด ๋ฏธ์‹œ๊ทธ๋„ ์‹œ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜
SuspendThread      โ†’ ๋Œ€์ƒ ์Šค๋ ˆ๋“œ Wait ์ƒํƒœ (์ž๊ธฐ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ X)

10. Windows ๋™๊ธฐํ™” ๊ฐ์ฒด๋ณ„ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ

MSVC ๋ฌธ์„œ ํŠธ๋ฆฌ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋น„์šฉ ์ฐจ์ด๋ฅผ ๋งŒ๋“œ๋Š” ์˜์—ญ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ โ€œ๋ฝโ€์ด๋ผ๋„ ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ์“ฐ๋А๋ƒ์— ๋”ฐ๋ผ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์ด 100๋ฐฐ๊นŒ์ง€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

๋น„์šฉ ์ŠคํŽ™ํŠธ๋Ÿผ (๋‚ฎ์Œ โ†’ ๋†’์Œ)

๊ฐ์ฒด์˜์—ญ๊ฒฝํ•ฉ ์‹œ ๋™์ž‘ํ•œ ํšŒ ๋น„์šฉํ”„๋กœ์„ธ์Šค ๊ฐ„
std::atomic (lock-free)์‚ฌ์šฉ์ž ๋ชจ๋“œCPU ๋ช…๋ น์œผ๋กœ ์žฌ์‹œ๋„์ˆ˜ nsX
Critical Section์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ์งง๊ฒŒ spin โ†’ ๊ทธ๋ž˜๋„ ์•ˆ ๋˜๋ฉด ์ปค๋„ ์ง„์ž…50~100 ns (๋ฌด๊ฒฝํ•ฉ)X (๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋งŒ)
SRWLock์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ๋น„์Šท50~100 nsX
Condition Variable์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ SleepConditionVariableSRW๋กœ ๋Œ€๊ธฐ๋น„์ŠทX
Mutex (์ปค๋„ ๊ฐ์ฒด)์ปค๋„ ๋ชจ๋“œํ•ญ์ƒ ์ปค๋„ ์ง„์ž…1~3 ฮผsO
Event์ปค๋„ ๋ชจ๋“œํ•ญ์ƒ ์ปค๋„ ์ง„์ž…๋น„์ŠทO
Semaphore์ปค๋„ ๋ชจ๋“œํ•ญ์ƒ ์ปค๋„ ์ง„์ž…๋น„์ŠทO

Critical Section โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ 

1
2
3
4
5
6
7
8
9
10
11
12
#include <windows.h>

CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
// ๋˜๋Š” spin count ์ง€์ • (๊ฒฝํ•ฉ ์‹œ spinํ•  ํšŸ์ˆ˜)
InitializeCriticalSectionAndSpinCount(&cs, 4000);

EnterCriticalSection(&cs);
// ์ž„๊ณ„ ๊ตฌ์—ญ
LeaveCriticalSection(&cs);

DeleteCriticalSection(&cs);

๋‚ด๋ถ€ ๋™์ž‘:

  1. EnterCriticalSection ์ง„์ž… โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ๋ฝ ์นด์šดํ„ฐ atomic ์ฆ๊ฐ€ ์‹œ๋„
  2. ๋ฝ์ด ๋น„์–ด์žˆ์œผ๋ฉด ์ฆ‰์‹œ ํš๋“ (์ปค๋„ ์ง„์ž… ์—†์Œ, ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ)
  3. ๋ฝ์ด ์žกํ˜€์žˆ์œผ๋ฉด SpinCount ๋งŒํผ spin (_mm_pause ๋ฐ˜๋ณต)
  4. ๊ทธ๋ž˜๋„ ๋ชป ์žก์œผ๋ฉด ๊ทธ๋•Œ ์ปค๋„ ์ง„์ž… โ†’ ์ด๋ฒคํŠธ ๊ฐ์ฒด์—์„œ ๋Œ€๊ธฐ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

ํ•ต์‹ฌ ํŠน์„ฑ:

  • ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ (์ปค๋„ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ์— ์นด์šดํ„ฐ ๋ณด๊ด€)
  • ์žฌ์ง„์ž… ๊ฐ€๋Šฅ (recursive) โ€” ๊ฐ™์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ Enter ๊ฐ€๋Šฅ
  • ๋ฌด๊ฒฝํ•ฉ ์ผ€์ด์Šค์—์„œ 50~100 nanosecond โ€” Mutex์˜ 20~50๋ฐฐ ๋น ๋ฆ„

SRWLock (Slim Reader/Writer Lock) โ€” Vista+

1
2
3
4
5
6
7
8
9
SRWLOCK lock = SRWLOCK_INIT;

// ์ฝ๊ธฐ ๋ฝ (์—ฌ๋Ÿฌ reader ๋™์‹œ ๊ฐ€๋Šฅ)
AcquireSRWLockShared(&lock);
ReleaseSRWLockShared(&lock);

// ์“ฐ๊ธฐ ๋ฝ (๋ฐฐํƒ€์ )
AcquireSRWLockExclusive(&lock);
ReleaseSRWLockExclusive(&lock);

ํŠน์„ฑ:

  • R/W ๋ถ„๋ฆฌ โ€” reader๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๊ฐœ, writer๋Š” ํ•˜๋‚˜๋งŒ
  • Critical Section๋ณด๋‹ค ๊ฐ€๋ณ๊ณ , ๊ฒฝํ•ฉ ์‹œ spin ํ›„ ์ปค๋„ ๋Œ€๊ธฐ
  • ์žฌ์ง„์ž… ๋ถˆ๊ฐ€ โ€” ๊ฐ™์€ ์Šค๋ ˆ๋“œ๊ฐ€ Acquire ๋‘ ๋ฒˆ ํ•˜๋ฉด ๋ฐ๋“œ๋ฝ
  • read ๋น„์ค‘์ด ํฐ ์ž๋ฃŒ๊ตฌ์กฐ(์ž์ฃผ ์ฝํžˆ๋Š” ์บ์‹œ ๋“ฑ)์—์„œ Critical Section๋ณด๋‹ค ์œ ๋ฆฌ
  • C++ ํ‘œ์ค€ std::shared_mutex๊ฐ€ MSVC์—์„  SRWLock ์œ„์— ๊ตฌํ˜„๋จ

Mutex / Event / Semaphore โ€” ํ•ญ์ƒ ์ปค๋„

1
2
3
4
5
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("MyMutex"));
WaitForSingleObject(hMutex, INFINITE);  // ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…
// ์ž„๊ณ„ ๊ตฌ์—ญ
ReleaseMutex(hMutex);
CloseHandle(hMutex);

ํŠน์„ฑ:

  • ์ปค๋„ ๊ฐ์ฒด โ€” WaitForSingleObject๋กœ ๋Œ€๊ธฐ โ†’ ํ•ญ์ƒ ์ปค๋„ ์ง„์ž… โ†’ ํ•ญ์ƒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๊ฐ€๋Šฅ
  • ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ  ๊ฐ€๋Šฅ โ€” ์ด๋ฆ„์„ ์ฃผ๋ฉด ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ OpenMutex๋กœ ์—ด ์ˆ˜ ์žˆ์Œ
  • ๋ฌด๊ฒฝํ•ฉ์ด๋ผ๋„ 1~3 ฮผs โ€” Critical Section์˜ 20~50๋ฐฐ ๋น„์‹ธ๋‹ค
  • Event๋Š” ์‹œ๊ทธ๋„ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด(SetEvent/ResetEvent), Semaphore๋Š” ์นด์šดํ„ฐ๋ฅผ ๊ฐ€์ง€๋Š” ๋ฝ

Condition Variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SRWLOCK lock = SRWLOCK_INIT;
CONDITION_VARIABLE cv = CONDITION_VARIABLE_INIT;

// ๋Œ€๊ธฐ ์ธก
AcquireSRWLockExclusive(&lock);
while (!ready) {
    SleepConditionVariableSRW(&cv, &lock, INFINITE, 0);
    // ์ž๋™์œผ๋กœ ๋ฝ ํ•ด์ œ โ†’ ๋Œ€๊ธฐ โ†’ ๊นจ์–ด๋‚˜๋ฉด ๋ฝ ์žฌํš๋“
}
AcquireSRWLockExclusive ํ•ด์ œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘

// ๊นจ์šฐ๊ธฐ ์ธก
AcquireSRWLockExclusive(&lock);
ready = TRUE;
ReleaseSRWLockExclusive(&lock);
WakeConditionVariable(&cv);  // ๋˜๋Š” WakeAllConditionVariable

ํŠน์„ฑ:

  • ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„  โ€” SRWLock ์œ„์—์„œ ๋™์ž‘
  • C++ std::condition_variable์ด MSVC์—์„  ์ด๊ฑธ ๋ž˜ํ•‘

์„ ํƒ ๊ฐ€์ด๋“œ

1
2
3
4
5
๊ฐ™์€ ํ”„๋กœ์„ธ์Šค, ์งง์€ ์ž„๊ณ„ ๊ตฌ์—ญ, ์žฌ์ง„์ž… ํ•„์š”    โ†’ Critical Section
๊ฐ™์€ ํ”„๋กœ์„ธ์Šค, read ๋น„์ค‘ ํผ                   โ†’ SRWLock
๊ฐ™์€ ํ”„๋กœ์„ธ์Šค, ๋‹จ์ผ ์นด์šดํ„ฐ read-modify-write  โ†’ std::atomic (lock-free)
๊ฐ™์€ ํ”„๋กœ์„ธ์Šค, ์กฐ๊ฑด ๋Œ€๊ธฐ ํŒจํ„ด                 โ†’ Condition Variable + SRWLock
ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ  ํ•„์š”                         โ†’ Mutex / Event / Semaphore

MSVC ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด SRWLock๊ณผ Critical Section์€ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ๋™๊ธฐํ™” ์˜ต์…˜์ด๊ณ , ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋ฌด๊ฑฐ์šด ์ปค๋„ ๊ฐ์ฒด๋ฅผ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


11. Concurrency Runtime / PPL โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์Šค์ผ€์ค„๋Ÿฌ

MSVC๊ฐ€ ์ œ๊ณตํ•˜๋Š” Concurrency Runtime(/cpp/parallel/concrt/)์€ OS ์œ„์— ์‚ฌ์šฉ์ž ๋ชจ๋“œ Task Scheduler๋ฅผ ๋‘์–ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ๋” ์ค„์ž…๋‹ˆ๋‹ค. PPL(Parallel Patterns Library) ์ด ๊ทธ ์œ„์— ์–นํžŒ ๊ณ ์ˆ˜์ค€ API์ž…๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๊ตฌ์„ฑ์š”์†Œ

1
2
3
4
5
6
7
8
โ”Œโ”€ PPL (Parallel Patterns Library) โ€” ๊ณ ์ˆ˜์ค€ ์•Œ๊ณ ๋ฆฌ์ฆ˜
โ”‚   parallel_for, parallel_for_each, parallel_invoke, task<T>
โ”‚
โ”œโ”€ Agents Library โ€” ๋ฉ”์‹œ์ง€ ํŒจ์‹ฑ ๋ชจ๋ธ
โ”‚   agent, message_block
โ”‚
โ””โ”€ Concurrency Runtime โ€” ๊ทธ ์•„๋ž˜ Task Scheduler
    Scheduler, ScheduleGroup, Context, Task

Task Scheduler์˜ ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜

1. Work Stealing โ€” ๋ถ€ํ•˜ ๋ถ„์‚ฐ

๊ฐ ์›Œ์ปค ์Šค๋ ˆ๋“œ๊ฐ€ ์ž๊ธฐ ์ž‘์—… ํ๋ฅผ ๊ฐ€์ง€๊ณ , ํ•œ๊ฐ€ํ•œ ์›Œ์ปค๊ฐ€ ๋‹ค๋ฅธ ์›Œ์ปค์˜ ํ ๋์—์„œ ์ž‘์—…์„ ํ›”์นฉ๋‹ˆ๋‹ค(steal). ํ์˜ ์–‘ ๋์„ ๋‹ค๋ฅด๊ฒŒ ์“ฐ๋Š” deque ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ผ ๋ฝ ๊ฒฝํ•ฉ์ด ๊ฑฐ์˜ ์—†๊ณ , ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์ด ๋ถ€ํ•˜ ๋ถ„์‚ฐ์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
Worker 1 ํ: [T1, T2, T3, T4]    โ† ์ž๊ธฐ๋Š” ์•ž์—์„œ pop
Worker 2 ํ: []                   โ† ๋น„์—ˆ์Œ
                                    โ†“ steal!
Worker 2 ํ: []  โ† Worker 1 ํ ๋’ค์—์„œ T4 ๊ฐ€์ ธ๊ฐ
Worker 1 ํ: [T1, T2, T3]

2. Context::Block / Yield / Unblock โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์–‘๋ณด

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <concrt.h>

void MyTask() {
    // ... ์ž‘์—… ...

    // ์ž๋ฐœ์  ์–‘๋ณด โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ, ์ปค๋„ ์ง„์ž… ์—†์Œ
    Concurrency::Context::Yield();

    // ๋ช…์‹œ์  ๋ธ”๋ก (๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๊ฐ€ Unblock ํ˜ธ์ถœ ์ „๊นŒ์ง€ ๋Œ€๊ธฐ)
    Concurrency::Context::Block();

    // ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๋ฅผ ๊นจ์›€
    otherContext->Unblock();
}

Context::Yield๋Š” ๊ฐ™์€ ์Šค์ผ€์ค„๋Ÿฌ ์•ˆ์˜ ๋‹ค๋ฅธ ready Task๋กœ ์–‘๋ณดํ•ฉ๋‹ˆ๋‹ค โ€” OS ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์ด ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์Šคํƒ ์ „ํ™˜๋งŒ ์ผ์œผํ‚ต๋‹ˆ๋‹ค. Fiber์™€ ๋น„์Šทํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ConcRT๊ฐ€ ์ถ”์ƒํ™”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

3. Oversubscription โ€” ์˜๋„์  ๊ณผ๋‹ค ๊ตฌ๋…

1
2
3
4
Concurrency::Context::Oversubscribe(true);
// ๋ธ”๋กœํ‚น ํ˜ธ์ถœ (์˜ˆ: I/O)
DoLongIO();
Concurrency::Context::Oversubscribe(false);

๋ธ”๋กœํ‚น ํ˜ธ์ถœ ์ง์ „์— Oversubscribe(true)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ConcRT๊ฐ€ ์ž„์‹œ๋กœ ์ถ”๊ฐ€ ์›Œ์ปค๋ฅผ ๋„์›Œ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์Šค๋ ˆ๋“œ๊ฐ€ ํ’€๋ ค๋‚˜๋ฉด ๋‹ค์‹œ ์ •์ƒ ์šด์˜. CPU-bound ์ž‘์—…์—์„  ์ฝ”์–ด ์ˆ˜๋งŒํผ ์Šค๋ ˆ๋“œ๋ฅผ ๋„์šฐ๋Š” ๊ฒŒ ์ผ๋ฐ˜์ ์ด์ง€๋งŒ, I/O ๋น„์ค‘์ด ํฐ ์›Œํฌ๋กœ๋“œ์—์„  oversubscription์ด throughput์„ ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค.

PPL โ€” ๊ณ ์ˆ˜์ค€ API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <ppl.h>

// ๋ณ‘๋ ฌ for
Concurrency::parallel_for(0, 1000, [](int i) {
    HeavyWork(i);
});

// ๋ณ‘๋ ฌ for_each
std::vector<int> v(1000);
Concurrency::parallel_for_each(v.begin(), v.end(), [](int& x) {
    x *= 2;
});

// ๋™์‹œ task ์‹คํ–‰
Concurrency::parallel_invoke(
    []{ TaskA(); },
    []{ TaskB(); },
    []{ TaskC(); }
);

// task ๊ฐ์ฒด โ€” ์˜์กด์„ฑ๊ณผ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
Concurrency::task<int> t = Concurrency::create_task([]{ return ComputeResult(); });
t.then([](int result){
    UseResult(result);
});

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ ์ ˆ๊ฐ ํšจ๊ณผ

ConcRT์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋Š” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์ž‘์—… ์Šค์ผ€์ค„๋ง์ด ๋๋‚˜๋Š” ์ผ€์ด์Šค๋ฅผ ๋Š˜๋ ค OS ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ค„์ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 1000๊ฐœ์˜ parallel_for ๋ฐ˜๋ณต์„ OS ์Šค๋ ˆ๋“œ 1000๊ฐœ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด 1000๋ฒˆ ๊ฐ€๊นŒ์ด ์ผ์–ด๋‚˜์ง€๋งŒ, ConcRT๋Š” ์ฝ”์–ด ์ˆ˜๋งŒํผ์˜ ์Šค๋ ˆ๋“œ ํ’€์—์„œ work stealing์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ OS ์Šค์œ„์นญ์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.

MSVC ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด Concurrency Runtime์€ Windows์˜ ํ‘œ์ค€ ์Šค๋ ˆ๋“œ ํ’€ API์™€๋Š” ๋ณ„๊ฐœ์˜ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ๊ฐ€์ง€๋ฉฐ, parallel_for/task ๊ฐ™์€ ๊ณ ์ˆ˜์ค€ ์ถ”์ƒํ™”๋ฅผ ํ†ตํ•ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋นˆ๋„๋ฅผ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค.


12. Fiber API์™€ UMS โ€” ์ปค๋„ ๊ฐœ์ž… ์—†๋Š” ํ˜‘๋ ฅ์  ์Šค์œ„์นญ

Fiber โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์Šค๋ ˆ๋“œ

Fiber๋Š” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ๋งŒ ๊ด€๋ฆฌ๋˜๋Š” ํ˜‘๋ ฅ์  ์‹คํ–‰ ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. OS ์ปค๋„์€ Fiber๋ฅผ ๋ชจ๋ฅด๊ณ , ํ•œ OS ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์—ฌ๋Ÿฌ Fiber๊ฐ€ ์ž๊ธฐ๋“ค๋ผ๋ฆฌ SPยทPC๋ฅผ ๋ฐ”๊ฟ”์น˜๊ธฐํ•˜๋ฉฐ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <windows.h>

VOID CALLBACK FiberA(PVOID lpParameter) {
    while (true) {
        printf("Fiber A\n");
        SwitchToFiber(g_FiberB);  // B๋กœ ์ „ํ™˜ โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ, ์ˆ˜์‹ญ ns
    }
}

VOID CALLBACK FiberB(PVOID lpParameter) {
    while (true) {
        printf("Fiber B\n");
        SwitchToFiber(g_FiberA);
    }
}

LPVOID g_FiberMain;
LPVOID g_FiberA;
LPVOID g_FiberB;

int main() {
    g_FiberMain = ConvertThreadToFiber(NULL);  // ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ Fiber๋กœ ๋ณ€ํ™˜
    g_FiberA = CreateFiber(0, FiberA, NULL);
    g_FiberB = CreateFiber(0, FiberB, NULL);

    SwitchToFiber(g_FiberA);  // ์‹œ์ž‘

    DeleteFiber(g_FiberA);
    DeleteFiber(g_FiberB);
    ConvertFiberToThread();
    return 0;
}

Fiber ํŠน์„ฑ

ํ•ญ๋ชฉFiberOS ์Šค๋ ˆ๋“œ
๊ด€๋ฆฌ ์ฃผ์ฒด์‚ฌ์šฉ์ž ๋ชจ๋“œ (์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)OS ์ปค๋„
์Šค์œ„์นญ ๋น„์šฉ์ˆ˜์‹ญ ns1~5 ฮผs (์Šค๋ ˆ๋“œ ์ „ํ™˜)
์Šค์œ„์นญ ํŠธ๋ฆฌ๊ฑฐSwitchToFiber (์ž๋ฐœ์ )ํƒ€์ด๋จธยทI/Oยท๋™๊ธฐํ™” (๊ฐ•์ œ ๊ฐ€๋Šฅ)
๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ™œ์šฉ๋ถˆ๊ฐ€ (ํ•œ OS ์Šค๋ ˆ๋“œ ์•ˆ)๊ฐ€๋Šฅ
์‹œ์Šคํ…œ ์ฝœ ์ฐจ๋‹จ ์‹œํ˜ธ์ŠคํŠธ OS ์Šค๋ ˆ๋“œ ์ฐจ๋‹จ โ†’ ๋‹ค๋ฅธ Fiber๋„ ๋ฉˆ์ถค๊ทธ ์Šค๋ ˆ๋“œ๋งŒ ์ฐจ๋‹จ
์‚ฌ์šฉ์ฒ˜์‚ฌ์šฉ์ž ๋ชจ๋“œ ์ฝ”๋ฃจํ‹ด, ๊ฒŒ์ž„ ์—”์ง„ ์ž‘์—… ์‹œ์Šคํ…œ์ผ๋ฐ˜ ๋™์‹œ์„ฑ

Fiber์˜ ํ•œ๊ณ„

OS ์ปค๋„์€ Fiber๋ฅผ ๋ชจ๋ฅด๋ฏ€๋กœ ์‹œ์Šคํ…œ ์ฝœ์ด ๋ธ”๋กœํ‚น๋˜๋ฉด ๊ทธ OS ์Šค๋ ˆ๋“œ ์ „์ฒด๊ฐ€ ๋ฉˆ์ถ”๊ณ , ๊ทธ ์•ˆ์˜ ๋‹ค๋ฅธ Fiber๋“ค๋„ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Fiber๋Š” ์ˆœ์ˆ˜ CPU-bound ์ž‘์—…์— ์ ํ•ฉํ•˜๊ณ , I/O ์ž‘์—…๊ณผ ์„ž์ด๋ฉด ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ๋˜ ๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ™œ์šฉ์ด ์•ˆ ๋ฉ๋‹ˆ๋‹ค โ€” ํ•œ OS ์Šค๋ ˆ๋“œ ์•ˆ์˜ Fiber๋“ค์ด๋ผ ์ฝ”์–ด ํ•˜๋‚˜์—์„œ๋งŒ ๋•๋‹ˆ๋‹ค(์ฝ”์–ด๋ฅผ ๋” ์“ฐ๋ ค๋ฉด OS ์Šค๋ ˆ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋„์šฐ๊ณ  ๊ฐ์ž ์•ˆ์— Fiber๋“ค์„ ๋‘ฌ์•ผ ํ•จ).

Fiber์˜ ์‹ค๋ฌด ์‚ฌ๋ก€

  • ๊ฒŒ์ž„ ์—”์ง„์˜ ์ž‘์—… ์‹œ์Šคํ…œ (Naughty Dog์˜ GDC ๋ฐœํ‘œ โ€œParallelizing the Naughty Dog Engineโ€ ์ฐธ๊ณ ) โ€” ์ˆ˜๋ฐฑ ๊ฐœ์˜ ์ž‘์—…์„ OS ์Šค๋ ˆ๋“œ ํ’€ + Fiber๋กœ ๋ฌถ์–ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ๊ทน๋‹จ์ ์œผ๋กœ ์ค„์ž„
  • C++20 ์ฝ”๋ฃจํ‹ด ์ด์ „์˜ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์  ์Šค์ผ€์ค„๋ง โ€” ํ˜„์žฌ๋Š” ์ฝ”๋ฃจํ‹ด์ด ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€์•ˆ
  • ๋ ˆ๊ฑฐ์‹œ ํ˜‘๋ ฅ์  ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น ์‹œ๋ฎฌ๋ ˆ์ด์…˜

UMS (User-Mode Scheduling) โ€” ์ ˆ์ถฉ ๋ชจ๋ธ

UMS๋Š” ์ปค๋„์€ ์Šค๋ ˆ๋“œ๋ฅผ ์•Œ์ง€๋งŒ ์Šค์ผ€์ค„๋ง์€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ํ•˜๋Š” Windows 7+ x64์˜ ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. Fiber์˜ ํ•œ๊ณ„(์‹œ์Šคํ…œ ์ฝœ ๋ธ”๋กœํ‚น ์‹œ ์ „์ฒด ๋ฉˆ์ถค)๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์‹œ๋„์˜€์Šต๋‹ˆ๋‹ค.

1
2
3
Fiber:        OS ๋ชจ๋ฆ„ โ†’ I/O ๋ธ”๋กœํ‚น ์‹œ ํ˜ธ์ŠคํŠธ ์Šค๋ ˆ๋“œ ์ „์ฒด ๋ฉˆ์ถค
์ผ๋ฐ˜ ์Šค๋ ˆ๋“œ:   OS ๊ด€๋ฆฌ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์‹ธ๋‚˜ I/O ์ž์œ 
UMS:          OS๋Š” ์•Œ์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์Šค์ผ€์ค„๋ง โ†’ I/O ์‹œ OS๊ฐ€ ์‚ฌ์šฉ์ž ์Šค์ผ€์ค„๋Ÿฌ์— ์•Œ๋ฆผ

UMS ๋™์ž‘:

  1. UMS ์›Œ์ปค ์Šค๋ ˆ๋“œ๊ฐ€ ์‹œ์Šคํ…œ ์ฝœ์—์„œ ๋ธ”๋กœํ‚น๋˜๋ฉด OS๊ฐ€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์Šค์ผ€์ค„๋Ÿฌ์— ์ฝœ๋ฐฑ์œผ๋กœ ์•Œ๋ฆผ
  2. ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค๋ฅธ UMS ์›Œ์ปค๋ฅผ ์ฆ‰์‹œ ๋””์ŠคํŒจ์น˜ (์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ๊ฒฐ์ •)
  3. ๋ธ”๋กœํ‚น ํ’€๋ฆฌ๋ฉด OS๊ฐ€ ๋‹ค์‹œ ์•Œ๋ฆผ โ†’ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ์žฌ๋ฐฐ์น˜

UMS๋Š” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ด ๋ณต์žกํ•ด์„œ ์‹ค๋ฌด ์ฑ„ํƒ๋ฅ ์€ ๋‚ฎ๊ณ , ํ˜„๋Œ€ Windows์—์„  Concurrency Runtime + ์ฝ”๋ฃจํ‹ด์ด ๋” ์ผ๋ฐ˜์ ์ธ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค. MSVC ๋ฌธ์„œ ํŠธ๋ฆฌ์—์„œ๋„ UMS๋Š” ๋ณ„๋„ ์„น์…˜์œผ๋กœ ๋‹ค๋ค„์ง€์ง€๋งŒ deprecated ํ‘œ์‹œ๊ฐ€ ๋ถ™๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Š˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ ๋น„๊ต (์ด์ •๋ฆฌ)

๋‹จ์œ„์Šค์œ„์นญ ๋น„์šฉ๋ฉ€ํ‹ฐ ์ฝ”์–ดI/O ๋ธ”๋กœํ‚น ์•ˆ์ „
Fiber (SwitchToFiber)~์ˆ˜์‹ญ nsXX
ConcRT Context::Yield~์ˆ˜์‹ญ~์ˆ˜๋ฐฑ nsO๋ถ€๋ถ„์ 
UMS~์ˆ˜๋ฐฑ ns~1 ฮผsOO
OS ์Šค๋ ˆ๋“œ (๊ฐ™์€ ํ”„๋กœ์„ธ์Šค)1~5 ฮผsOO
OS ํ”„๋กœ์„ธ์Šค5~20 ฮผsOO

13. C++ ํ‘œ์ค€ ๋™์‹œ์„ฑ์˜ Windows ๋งคํ•‘

std::thread โ†’ _beginthreadex โ†’ CreateThread

1
2
3
4
#include <thread>

std::thread t([]{ /* ์ž‘์—… */ });
t.join();

MSVC์˜ std::thread ๊ตฌํ˜„์€ ๋‚ด๋ถ€์ ์œผ๋กœ _beginthreadex๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์ด๊ฒŒ ๋‹ค์‹œ CreateThread๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. _beginthreadex๋ฅผ ๊ฑฐ์น˜๋Š” ์ด์œ ๋Š” CRT์˜ TLS ์ดˆ๊ธฐํ™”(stdio ๋ฝ, errno, strtok ๋“ฑ)๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
std::thread ์ƒ์„ฑ์ž
  โ†“
std::_Thrd_start (C ์ธํ„ฐํŽ˜์ด์Šค ์–ด๋Œ‘ํ„ฐ)
  โ†“
_beginthreadex (CRT TLS ์ดˆ๊ธฐํ™” ํฌํ•จ)
  โ†“
CreateThread (Win32 ์ปค๋„ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ)
  โ†“
์ƒˆ TCB ์ƒ์„ฑ โ†’ Ready ํ โ†’ ์Šค์ผ€์ค„๋Ÿฌ ๋””์ŠคํŒจ์น˜ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋กœ ์‹œ์ž‘

์Šค๋ ˆ๋“œ ์ข…๋ฃŒ๋„ _endthreadex๋กœ CRT cleanup์„ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ raw CreateThread + ExitThread๋ฅผ ์ง์ ‘ ์“ฐ๋ฉด CRT๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” MSVC ๋ฌธ์„œ๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ _beginthreadex ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

std::mutex โ†’ SRWLock or Critical Section

1
2
3
4
#include <mutex>

std::mutex m;
std::lock_guard<std::mutex> lock(m);  // ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์€ SRWLock ์ˆ˜์ค€

MSVC์˜ std::mutex๋Š” Visual Studio 2019 16.x ์ดํ›„ SRWLock ์œ„์— ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค(์ด์ „ ๋ฒ„์ „์€ Critical Section). ๋‘˜ ๋‹ค ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ์ด๋ผ ๋ฌด๊ฒฝํ•ฉ ์ผ€์ด์Šค์—์„  ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

std::shared_mutex โ†’ SRWLock (R/W ๋ถ„๋ฆฌ)

1
2
3
4
5
#include <shared_mutex>

std::shared_mutex sm;
std::shared_lock lock(sm);  // ์ฝ๊ธฐ ๋ฝ โ€” ์—ฌ๋Ÿฌ reader ๋™์‹œ
// ๋˜๋Š” std::unique_lock โ€” ์“ฐ๊ธฐ ๋ฝ

SRWLock์˜ R/W ๋ถ„๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ๋…ธ์ถœ. ์ž์ฃผ ์ฝ๊ณ  ๊ฐ€๋” ์“ฐ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ(์„ค์ •ยท์บ์‹œ)์— ์œ ๋ฆฌ.

std::condition_variable โ†’ Windows Condition Variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
bool ready = false;

// ๋Œ€๊ธฐ ์ธก
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, []{ return ready; });
// ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ๋Œ€๊ธฐ โ†’ ๊นจ์šฐ๊ธฐ ์‹œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜

// ๊นจ์šฐ๊ธฐ ์ธก
{ std::lock_guard lock(m); ready = true; }
cv.notify_one();

MSVC๋Š” Windows Condition Variable + SRWLock ์กฐํ•ฉ์œผ๋กœ ๊ตฌํ˜„. ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ์ด๋ผ ๊ฐ€๋ฒผ์›€.

std::atomic<T> โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์Œ

1
2
3
4
#include <atomic>

std::atomic<int> counter{0};
counter.fetch_add(1);  // CPU ๋ช…๋ น(LOCK XADD) โ€” OS ์ง„์ž… ์—†์Œ, ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์Œ

Lock-free ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ธฐ์ดˆ. CPU์˜ LOCK ์ ‘๋‘์‚ฌ ๋ช…๋ น(LOCK XADD, LOCK CMPXCHG ๋“ฑ)์„ ์‚ฌ์šฉํ•ด ๋‹จ์ผ ๋ช…๋ น ์ˆ˜์ค€์—์„œ ์›์ž์„ฑ์„ ๋ณด์žฅ. ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ์œ ์ผํ•œ ๋™๊ธฐํ™” ๋„๊ตฌ โ€” ๋‹จ์ˆœ ์นด์šดํ„ฐยทํ”Œ๋ž˜๊ทธยทCAS ํŒจํ„ด์— ๊ฐ€์žฅ ๋น ๋ฆ„.

std::async / std::future โ†’ ์Šค๋ ˆ๋“œ ํ’€ ๋˜๋Š” ์ƒˆ ์Šค๋ ˆ๋“œ

1
2
3
4
#include <future>

std::future<int> f = std::async(std::launch::async, []{ return Compute(); });
int result = f.get();

std::launch::async๋Š” ์ƒˆ ์Šค๋ ˆ๋“œ, std::launch::deferred๋Š” get() ํ˜ธ์ถœ ์‹œ์ ์— ๋™๊ธฐ ์‹คํ–‰. ์ •์ฑ… ๋ฏธ์ง€์ • ์‹œ ๊ตฌํ˜„ ์ •์˜(MSVC๋Š” ๋ณดํ†ต deferred ๋˜๋Š” thread pool). MSVC์˜ thread pool ๊ตฌํ˜„์€ Windows์˜ ThreadPool API(SubmitThreadpoolWork)๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

std::jthread (C++20) โ€” RAII ์ž๋™ join

1
2
3
4
5
6
7
8
#include <thread>

{
    std::jthread jt([](std::stop_token stoken){
        while (!stoken.stop_requested()) { /* ์ž‘์—… */ }
    });
    // ์†Œ๋ฉธ์ž๊ฐ€ ์ž๋™์œผ๋กœ stop ์š”์ฒญ + join
}

C++20๋ถ€ํ„ฐ ํ‘œ์ค€ํ™”๋œ ์ž๋™ join ์Šค๋ ˆ๋“œ. 9๋ฒˆ RAII์˜ ๋™์‹œ์„ฑ ์‘์šฉ.

๋งคํ•‘ ์ข…ํ•ฉ ํ‘œ

C++ ํ‘œ์ค€Windows ๊ตฌํ˜„์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ
std::thread_beginthreadex โ†’ CreateThread์ƒ์„ฑยท์ข…๋ฃŒ ์‹œ
std::jthread (C++20)๊ฐ™์Œ + stop_token๊ฐ™์Œ
std::mutexSRWLock (๋˜๋Š” Critical Section)๊ฒฝํ•ฉ ์‹œ๋งŒ
std::shared_mutexSRWLock (R/W)๊ฒฝํ•ฉ ์‹œ๋งŒ
std::condition_variableWindows Condition Variable๋Œ€๊ธฐยท๊นจ์šฐ๊ธฐ ์‹œ
std::atomic<T>CPU ๋ช…๋ น (LOCK XADD ๋“ฑ)์—†์Œ
std::asyncThreadPool API ๋˜๋Š” ์ƒˆ ์Šค๋ ˆ๋“œ์ž‘์—… ๋””์ŠคํŒจ์น˜ ์‹œ
std::this_thread::yieldSwitchToThreadํ›„๋ณด ์žˆ์„ ๋•Œ
std::this_thread::sleep_forSleep ๋˜๋Š” high-res ํƒ€์ด๋จธํ•ญ์ƒ

14. Thread Local Storage์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ

TLS์˜ ์—ญํ• 

TLS(Thread Local Storage, ์Šค๋ ˆ๋“œ ์ง€์—ญ ์ €์žฅ์†Œ)๋Š” ๋ณ€์ˆ˜๊ฐ€ ์Šค๋ ˆ๋“œ๋ณ„๋กœ ๋…๋ฆฝ๋œ ์Šฌ๋กฏ์„ ๊ฐ€์ง€๊ฒŒ ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ๋ณ€์ˆ˜ ์ด๋ฆ„์ด์ง€๋งŒ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ด…๋‹ˆ๋‹ค.

1
2
3
4
5
__declspec(thread) int g_counter = 0;  // MSVC TLS

void Worker() {
    g_counter++;  // ์ด ์Šค๋ ˆ๋“œ์˜ g_counter๋งŒ ์ฆ๊ฐ€ โ€” race condition ์—†์Œ!
}

ํ‘œ์ค€ C++์—์„  thread_local ํ‚ค์›Œ๋“œ(C++11)๊ฐ€ ๊ฐ™์€ ์—ญํ• :

1
thread_local int counter = 0;

TLS๋Š” ์–ด๋””์— ์ €์žฅ๋˜๋‚˜

์Šค๋ ˆ๋“œ๋ณ„ TLS ์Šฌ๋กฏ์€ TCB๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณ„๋„ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ TLS ๋ณ€์ˆ˜ ์ ‘๊ทผ์„ fs:[...](x86) / gs:[...](x64) ์„ธ๊ทธ๋จผํŠธ ๋ ˆ์ง€์Šคํ„ฐ ๊ธฐ์ค€ ์˜คํ”„์…‹์œผ๋กœ ๋ณ€ํ™˜ํ•ด, ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ TLS ์Šฌ๋กฏ์„ ์ž๋™์œผ๋กœ ์ฐพ์•„๊ฐ‘๋‹ˆ๋‹ค.

1
2
3
Windows x64 ๊ธฐ์ค€:
  gs:[0x30] = TEB (Thread Environment Block) ์ฃผ์†Œ
    โ””โ”€ TEB.ThreadLocalStoragePointer โ†’ ๊ทธ ์Šค๋ ˆ๋“œ์˜ TLS ์Šฌ๋กฏ ๋ฐฐ์—ด

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์‹œ TLS ๋ณด์กด

ํ•ต์‹ฌ์€ TLS๋Š” ์Šค๋ ˆ๋“œ ์ž๊ธฐ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์ฃผํ•˜๋ฏ€๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์‹œ ์ž๋™์œผ๋กœ ๋ณด์กด๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. OS๊ฐ€ TLS๋ฅผ ๋”ฐ๋กœ ์ €์žฅยท๋ณต์›ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค โ€” ๊ทธ์ € TCB(๋”ฐ๋ผ์„œ TEB์™€ TLS ํฌ์ธํ„ฐ)๊ฐ€ ์ƒˆ ์Šค๋ ˆ๋“œ ๊ฒƒ์œผ๋กœ ๋ฐ”๋€Œ๋ฉด gs:[...] ์ ‘๊ทผ์ด ์ž๋™์œผ๋กœ ์ƒˆ ์Šค๋ ˆ๋“œ์˜ TLS๋ฅผ ์ฐพ์•„๊ฐ‘๋‹ˆ๋‹ค.

1
2
3
์Šค๋ ˆ๋“œ A ์‹คํ–‰: gs ๋ ˆ์ง€์Šคํ„ฐ โ†’ A์˜ TEB โ†’ A์˜ TLS ์Šฌ๋กฏ
  โ†“ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ (gs ๋ ˆ์ง€์Šคํ„ฐ๋„ B์˜ ๊ฒƒ์œผ๋กœ ๊ต์ฒด)
์Šค๋ ˆ๋“œ B ์‹คํ–‰: gs ๋ ˆ์ง€์Šคํ„ฐ โ†’ B์˜ TEB โ†’ B์˜ TLS ์Šฌ๋กฏ

๋™์  TLS โ€” TlsAlloc / TlsGetValue

์ •์ (์ปดํŒŒ์ผ ํƒ€์ž„) TLS ์™ธ์— ๋™์ ์œผ๋กœ ์Šฌ๋กฏ์„ ํ• ๋‹นํ•˜๋Š” API๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

1
2
3
4
5
6
7
8
9
10
11
12
DWORD g_tlsIndex = TlsAlloc();  // ์Šฌ๋กฏ ๋ฒˆํ˜ธ ํ• ๋‹น (๋ณดํ†ต 64~1088 ๋ฒ”์œ„)

void SetData(int* data) {
    TlsSetValue(g_tlsIndex, data);  // ์ด ์Šค๋ ˆ๋“œ์˜ ์Šฌ๋กฏ์— ์ €์žฅ
}

int* GetData() {
    return (int*)TlsGetValue(g_tlsIndex);  // ์ด ์Šค๋ ˆ๋“œ์˜ ์Šฌ๋กฏ์—์„œ ๊บผ๋ƒ„
}

// ์ •๋ฆฌ
TlsFree(g_tlsIndex);

DLL์—์„œ ์ž์ฃผ ์“ฐ๋Š” ํŒจํ„ด โ€” DLL์ด ์–ด๋–ค ์Šค๋ ˆ๋“œ์—์„œ ํ˜ธ์ถœ๋˜๋Š”์ง€ ๋ชจ๋ฅผ ๋•Œ ์ž๊ธฐ๋งŒ์˜ ์Šค๋ ˆ๋“œ๋ณ„ ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌ.

CRT๊ฐ€ ์“ฐ๋Š” TLS

CRT ์ž์ฒด๊ฐ€ TLS๋ฅผ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

  • errno โ€” ์Šค๋ ˆ๋“œ๋ณ„ ์—๋Ÿฌ ์ฝ”๋“œ
  • strtok ๋‚ด๋ถ€ ์ƒํƒœ
  • stdio ์ŠคํŠธ๋ฆผ ๋ฝ
  • rand ๋‚ด๋ถ€ ์ƒํƒœ

๊ทธ๋ž˜์„œ raw CreateThread๋ฅผ ์“ฐ๋ฉด ์ด TLS๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•„ ๋ฏธ๋ฌ˜ํ•œ ๋ฒ„๊ทธ๊ฐ€ ์ƒ๊ธฐ๊ณ , _beginthreadex๊ฐ€ ๊ถŒ์žฅ๋˜๋Š” ์ด์œ ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

TLS์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์˜ํ–ฅ

  • ์ €์žฅยท๋ณต์› ์ง์ ‘ ๋น„์šฉ ์—†์Œ โ€” ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์ฃผ
  • ๊ฐ„์ ‘ ๋น„์šฉ์€ ์ผ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋™์ผ โ€” ์บ์‹œ ์ฝœ๋“œ ์˜ํ–ฅ ๋ฐ›์Œ
  • ๋‹จ, TLS ์˜์—ญ ์ž์ฒด๊ฐ€ ๋ณดํ†ต ์ž‘์•„์„œ(์ˆ˜ KB) ์บ์‹œ ์นœํ™”์ 
  • ์ •์  TLS๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ง์ ‘ ์˜คํ”„์…‹ ๊ณ„์‚ฐ โ†’ ๋น ๋ฆ„
  • ๋™์  TLS๋Š” TlsGetValue ํ•จ์ˆ˜ ํ˜ธ์ถœ โ†’ ์•ฝ๊ฐ„ ๋А๋ฆผ

MSVC ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด __declspec(thread)๋Š” ์ •์  ๋งํฌ ์‹œ์ ์— TLS ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋“ฑ๋ก๋˜๋ฉฐ, DLL์˜ ๋™์  ๋กœ๋”ฉ(LoadLibrary)๊ณผ ํ•จ๊ป˜ ์“ฐ๋ฉด ์ผ๋ถ€ ์ œ์•ฝ์ด ์žˆ์Šต๋‹ˆ๋‹ค(Vista ์ด์ „์—” ๋™์  ๋กœ๋”ฉ DLL์˜ __declspec(thread)๊ฐ€ ๋™์ž‘ ์•ˆ ํ•จ).


15. CRT ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์˜ต์…˜ โ€” /MT vs /MD

CRT ๋งํฌ ์˜ต์…˜ 4๊ฐ€์ง€

์˜ต์…˜์˜๋ฏธCRT ๋งํฌDLL/EXE
/MTMulti-Threaded (์ •์ )exe์— ์ •์  ๋งํฌ๋‹จ๋… EXE
/MTd์œ„์˜ ๋””๋ฒ„๊ทธ ๋นŒ๋“œ์ •์  ๋””๋ฒ„๊ทธ๋””๋ฒ„๊ทธ EXE
/MDMulti-threaded DLLDLL๋กœ ๋™์  ๋งํฌ (UCRT)ํ‘œ์ค€
/MDd์œ„์˜ ๋””๋ฒ„๊ทธ ๋นŒ๋“œ๋™์  ๋””๋ฒ„๊ทธ๋””๋ฒ„๊ทธ ํ‘œ์ค€

์ด์ „์— ์žˆ๋˜ /ML(Single-Threaded)์€ Visual Studio 2005๋ถ€ํ„ฐ ์‚ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค โ€” ๋ชจ๋“  ํ˜„๋Œ€ CRT๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์•ˆ์ „.

/MT (์ •์  CRT) ํŠน์„ฑ

1
2
3
4
5
EXE ์•ˆ์— CRT ์ฝ”๋“œ ํ†ต์งธ๋กœ ํฌํ•จ
  โ”œโ”€ ์žฅ์ : CRT DLL ์˜์กด์„ฑ ์—†์Œ (๋‹จ๋… ์‹คํ–‰, ๋ฐฐํฌ ๊ฐ„๋‹จ)
  โ”œโ”€ ๋‹จ์ : EXE ํฌ๊ธฐ ์ปค์ง (์ˆ˜ MB ์ถ”๊ฐ€)
  โ”œโ”€ ๋‹จ์ : CRT ๋ณด์•ˆ ํŒจ์น˜๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด ์žฌ์ปดํŒŒ์ผ ํ•„์š”
  โ””โ”€ ๋‹จ์ : ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๊ณผ CRT ์ธ์Šคํ„ด์Šค ๋ถ„๋ฆฌ โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™”

/MD (DLL CRT, UCRT) ํŠน์„ฑ

1
2
3
4
5
CRT๋ฅผ ucrtbase.dll / vcruntime140.dll์—์„œ ๋™์  ๋กœ๋“œ
  โ”œโ”€ ์žฅ์ : EXE ํฌ๊ธฐ ์ž‘์Œ
  โ”œโ”€ ์žฅ์ : Windows Update๋กœ CRT ํŒจ์น˜ ์ž๋™
  โ”œโ”€ ์žฅ์ : ๊ฐ™์€ CRT ์ธ์Šคํ„ด์Šค ๊ณต์œ  (๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ)
  โ””โ”€ ๋‹จ์ : CRT DLL ๋ฐฐํฌ ํ•„์š” (๋˜๋Š” ์‹œ์Šคํ…œ์— ์‚ฌ์ „ ์„ค์น˜)

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์ง€์ 

CRT๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ ์œ„ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฝ์„ ์”€. ์ด ๋ฝ์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์œ ๋ฐœํ•˜๋Š” ์ผ€์ด์Šค:

1. stdio ๋ฝ

1
printf("Hello\n");   // ๋‚ด๋ถ€์ ์œผ๋กœ _lock_file โ†’ ์ž„๊ณ„ ๊ตฌ์—ญ โ†’ unlock

stdout์„ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์“ฐ๋ฉด ์ถœ๋ ฅ์ด ์„ž์ด์ง€ ์•Š๊ฒŒ CRT๊ฐ€ ๋ฝ์„ ์žก์Šต๋‹ˆ๋‹ค. ๊ฒฝํ•ฉ์ด ์žฆ์œผ๋ฉด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„/์„œ๋ฒ„์—์„œ ๋งค ํ”„๋ ˆ์ž„ printf๋ฅผ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ํ˜ธ์ถœํ•˜๋ฉด ์˜์™ธ์˜ ๋ณ‘๋ชฉ์ด ๋ฉ๋‹ˆ๋‹ค โ€” ์ž์ฒด ๋กœ๊น… ์‹œ์Šคํ…œ(lock-free ํ + ํ•œ ์›Œ์ปค ์ถœ๋ ฅ)์ด ๊ถŒ์žฅ๋˜๋Š” ์ด์œ .

2. ํž™ ๋ฝ (malloc/new)

1
int* p = new int(42);  // ๋‚ด๋ถ€์ ์œผ๋กœ HeapAlloc โ†’ ํž™ ๋ฝ โ†’ ํ• ๋‹น โ†’ unlock

CRT ํž™(๋˜๋Š” Windows ์‹œ์Šคํ…œ ํž™)์ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์—์„œ ๊ณต์œ ๋˜๋‹ˆ ๋ฝ์ด ํ•„์š”. Low-Fragmentation Heap (LFH) ์ด ํ™œ์„ฑํ™”๋ผ ์žˆ์œผ๋ฉด ์Šค๋ ˆ๋“œ๋ณ„ ์บ์‹œ๋กœ ๋ฝ ๊ฒฝํ•ฉ์„ ์ค„์ด์ง€๋งŒ, ํฐ ํ• ๋‹น์ด๋‚˜ deallocation์€ ์—ฌ์ „ํžˆ ๊ธ€๋กœ๋ฒŒ ๋ฝ์„ ์žก์Šต๋‹ˆ๋‹ค.

ํšŒํ”ผ์ฑ…:

  • mimalloc, tcmalloc, jemalloc ๊ฐ™์€ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์นœํ™”์  ํ• ๋‹น๊ธฐ๋กœ ๊ต์ฒด
  • ๊ฐ์ฒด ํ’€ / ๋ฉ”๋ชจ๋ฆฌ ํ’€๋กœ ์ „์ฒด ํ• ๋‹น ๋นˆ๋„ ๋‚ฎ์ถ”๊ธฐ
  • ๊ฒŒ์ž„ ์—”์ง„๋“ค์ด ์ž์ฒด ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ์„ ์“ฐ๋Š” ์ด์œ 

3. errno, strtok, rand (TLS๋กœ ํšŒํ”ผ)

์ด ํ•จ์ˆ˜๋“ค์€ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์—์„œ race condition์ด ๋‚  ์ˆ˜ ์žˆ๋Š”๋ฐ, MSVC CRT๋Š” ์ด ์ƒํƒœ๋“ค์„ TLS์— ๋‘์–ด ๋ฝ ์—†์ด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  _beginthreadex ๊ฒฝ๋กœ๋กœ ์‹œ์ž‘ํ•œ ์Šค๋ ˆ๋“œ๋งŒ TLS๊ฐ€ ์ œ๋Œ€๋กœ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค(raw CreateThread๋Š” ์œ„ํ—˜).

4. static ์ง€์—ญ ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” (C++11+ thread-safe init)

1
2
3
4
void Foo() {
    static MyClass instance;  // C++11๋ถ€ํ„ฐ ์ดˆ๊ธฐํ™”๋Š” thread-safe ๋ณด์žฅ
    // ...
}

C++11๋ถ€ํ„ฐ ํ•จ์ˆ˜ ๋‚ด static ๋ณ€์ˆ˜์˜ ์ฒซ ํ˜ธ์ถœ ์ดˆ๊ธฐํ™”๋Š” ํ‘œ์ค€์ด thread-safe๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. MSVC๋Š” ์ด๊ฑธ atomic ํ”Œ๋ž˜๊ทธ + ๋ฝ์œผ๋กœ ๊ตฌํ˜„ โ€” ์ฒซ ํ˜ธ์ถœ ์‹œ ํ•œ ๋ฒˆ๋งŒ ๋ฝ์ด ์žกํžˆ๊ณ , ์ดํ›„ ํ˜ธ์ถœ์€ fast path๋กœ ๋ฝ ์—†์ด ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค(์ผ์ข…์˜ double-checked locking).

์ •๋ฆฌ

1
2
3
4
5
6
7
8
9
10
/MT vs /MD ์„ ํƒ์€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ์ง์ ‘ ์˜ํ–ฅ์€ ์ž‘์ง€๋งŒ
CRT ์ธ์Šคํ„ด์Šค ๊ณต์œ  ์—ฌ๋ถ€๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๋ฝ ๊ฒฝํ•ฉ์— ์˜ํ–ฅ:

๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ๋ชจ๋“  ๋ชจ๋“ˆ์ด /MD (๊ฐ™์€ CRT ๊ณต์œ )
  โ†’ ๊ฐ™์€ ํž™ ์‚ฌ์šฉ โ†’ ํ•œ ๊ณณ์—์„œ ํ• ๋‹นํ•˜๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ ํ•ด์ œ ์•ˆ์ „
  โ†’ ๋ฝ ๊ฒฝํ•ฉ์€ ํ•œ ๊ตฐ๋ฐ๋กœ ์ง‘์ค‘ (LFH๋กœ ์ผ๋ถ€ ์™„ํ™”)

์ผ๋ถ€๋Š” /MT, ์ผ๋ถ€๋Š” /MD
  โ†’ CRT ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ถ„๋ฆฌ๋จ โ†’ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ํ• ๋‹นํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ž๊ธฐ CRT๋กœ ํ•ด์ œ ์‹œ ํฌ๋ž˜์‹œ
  โ†’ ๊ฐ์ž ์ž๊ธฐ ํž™์ด๋ผ ๋ฝ ๊ฒฝํ•ฉ์€ ๋ถ„์‚ฐ๋˜์ง€๋งŒ ์œ„ํ—˜

MSVC ๋ฌธ์„œ๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ /MD ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ด ๋ฉ”๋ชจ๋ฆฌ/๋ฝ ์ผ๊ด€์„ฑ์ž…๋‹ˆ๋‹ค. ๋‹จ๋… ๋ฐฐํฌ๊ฐ€ ์ •๋ง ํ•„์š”ํ•  ๋•Œ๋งŒ /MT๋ฅผ ์“ฐ๋Š” ๊ฒŒ ์ปจ๋ฒค์…˜์ž…๋‹ˆ๋‹ค.


16. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ โ€” GameThread/RenderThread/RHIThread

์–ธ๋ฆฌ์–ผ ์—”์ง„์€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์Šค๋ ˆ๋“œ ์—ญํ• ์„ ๋ถ„๋ช…ํžˆ ๋‚˜๋ˆ„๊ณ , ๊ทธ ์‚ฌ์ด๋ฅผ ๋ช…๋ น ํ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ฑ„ํƒํ•ฉ๋‹ˆ๋‹ค.

3๋Œ€ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
โ”Œโ”€ Game Thread (๋ฉ”์ธ)
โ”‚   โ”œโ”€ AActor::Tick, Component::TickComponent
โ”‚   โ”œโ”€ UObject ์กฐ์ž‘ (์ƒ์„ฑ/์†Œ๋ฉธ/์†์„ฑ)
โ”‚   โ”œโ”€ Blueprint VM ์‹คํ–‰
โ”‚   โ”œโ”€ UI (UMG) ์ฒ˜๋ฆฌ
โ”‚   โ””โ”€ ์ž…๋ ฅ ์ฒ˜๋ฆฌ
โ”‚
โ”œโ”€ Render Thread (๋ณ‘๋ ฌ)
โ”‚   โ”œโ”€ Game Thread์—์„œ ๋ฐ›์€ ๋ช…๋ น์œผ๋กœ RHI ๋ช…๋ น ๋นŒ๋“œ
โ”‚   โ”œโ”€ Material ์ปดํŒŒ์ผยทLOD ๊ฒฐ์ •ยทculling
โ”‚   โ””โ”€ Mesh draw call ์ƒ์„ฑ
โ”‚
โ””โ”€ RHI Thread (๋ณ‘๋ ฌ)
    โ”œโ”€ Render Thread์—์„œ ๋ฐ›์€ RHI ๋ช…๋ น์„ GPU ๋“œ๋ผ์ด๋ฒ„์— ์ œ์ถœ
    โ”œโ”€ D3D12 / Vulkan / Metal API ํ˜ธ์ถœ
    โ””โ”€ ๋ฐฑ๋ฒ„ํผ swap, GPU sync

์„ธ ์Šค๋ ˆ๋“œ๊ฐ€ 1ํ”„๋ ˆ์ž„์”ฉ ์ฐจ์ด๋ฅผ ๋‘๊ณ  ํŒŒ์ดํ”„๋ผ์ด๋‹ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค โ€” Frame N์˜ Game์ด ๋๋‚˜๋ฉด Frame N์˜ Render๊ฐ€ ์‹œ์ž‘๋˜๋Š” ๋™์•ˆ Game์€ Frame N+1์„ ์‹œ์ž‘. ์ด๊ฒŒ GPU์™€ CPU๋ฅผ ๋™์‹œ์— ํ™œ์šฉํ•˜๋Š” ํ•ต์‹ฌ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์™œ ์Šค๋ ˆ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋‚˜ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๊ด€์ 

๊ฐ™์€ ์Šค๋ ˆ๋“œ ์•ˆ์— ๋ชจ๋“  ์ผ์„ ๋‹ค ๋„ฃ์œผ๋ฉด: ํ•œ ํ”„๋ ˆ์ž„ ์•ˆ์— ๊ฒŒ์ž„ ๋กœ์ง โ†’ ๋ Œ๋” ๋ช…๋ น ๋นŒ๋“œ โ†’ GPU ํ˜ธ์ถœ โ†’ swap์„ ์ˆœ์ฐจ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋ฏ€๋กœ GPU ๋Œ€๊ธฐ ์‹œ๊ฐ„๋งŒํผ CPU๊ฐ€ ๋†€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 60fps(16.6ms) ์•ˆ์— ๋‹ค ๋๋‚ด๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋ถ„๋ฆฌํ•˜๋ฉด: ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž๊ธฐ ์ „์šฉ ์ž‘์—…์— ์ง‘์ค‘ โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋ฐœ์ƒํ•ด๋„ ํ•œ ์ž‘์—… ์•ˆ์—์„œ๋งŒ ๋ฐœ์ƒ โ†’ ์บ์‹œ ์ฝœ๋“œ ์˜ํ–ฅ ์ตœ์†Œํ™”. ๊ทธ๋ฆฌ๊ณ  ๋ช…๋ น ํ๋กœ ํ†ต์‹ ํ•˜๋ฏ€๋กœ ๋™๊ธฐํ™” ๋นˆ๋„๊ฐ€ ๋‚ฎ์Œ โ†’ ๋ฝ ๊ฒฝํ•ฉ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ๋„ ์ ์Œ.

TaskGraph โ€” ์˜์กด์„ฑ ๊ธฐ๋ฐ˜ ์ž‘์—… ๋ถ„ํ• 

1
2
3
4
5
6
7
8
9
10
11
12
13
// ์ž‘์—… ์ •์˜
class FMyTask {
public:
    static FORCEINLINE TStatId GetStatId() { ... }
    ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyBackgroundThreadNormalTask; }
    static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
    void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) {
        // ์ž‘์—…
    }
};

// ๋””์ŠคํŒจ์น˜
TGraphTask<FMyTask>::CreateTask().ConstructAndDispatchWhenReady();

TaskGraph๋Š” ์ž‘์—…๋“ค์˜ ์˜์กด ๊ด€๊ณ„๋ฅผ ๊ทธ๋ž˜ํ”„๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ์›Œ์ปค ํ’€์—์„œ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. work stealing์„ ์‚ฌ์šฉํ•ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†์ด ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐํ•ฉ๋‹ˆ๋‹ค โ€” ConcRT์™€ ๊ฐ™์€ ์›๋ฆฌ.

ENamedThreads โ€” ์–ด๋””์„œ ์‹คํ–‰ํ• ์ง€ ๋ช…์‹œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
AsyncTask(ENamedThreads::GameThread, [this]() {
    // ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ โ€” UObject ์•ˆ์ „
    MyActor->SetActorLocation(NewLocation);
});

AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, []() {
    // ์›Œ์ปค ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ โ€” ๋ฌด๊ฑฐ์šด ์ž‘์—…
    HeavyComputation();

    // ๊ฒฐ๊ณผ๋Š” ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ๋กœ
    AsyncTask(ENamedThreads::GameThread, []() {
        UpdateUI();
    });
});

์ด ํŒจํ„ด์ด ์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ํ”ํ•ฉ๋‹ˆ๋‹ค โ€” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฌด๊ฑฐ์šด ์ผ, ๋๋‚˜๋ฉด ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ๋กœ ๊ฒฐ๊ณผ ์ „๋‹ฌ. ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ๋‘ ๋ฒˆ ์ผ์–ด๋‚˜์ง€๋งŒ, ๋ฌด๊ฑฐ์šด ์ผ์ด ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ๋ฅผ ๋ง‰์ง€ ์•Š์œผ๋ฏ€๋กœ ํ”„๋ ˆ์ž„์œจ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

FRunnableThread โ€” OS ์Šค๋ ˆ๋“œ ์ง์ ‘ ์ƒ์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class FMyWorker : public FRunnable {
public:
    virtual bool Init() override { return true; }
    virtual uint32 Run() override {
        while (!bStop) {
            // ์ž‘์—…
        }
        return 0;
    }
    virtual void Stop() override { bStop = true; }
    virtual void Exit() override { }
private:
    FThreadSafeBool bStop;
};

FMyWorker* worker = new FMyWorker();
FRunnableThread* thread = FRunnableThread::Create(
    worker,
    TEXT("MyWorker"),
    0,                       // ๊ธฐ๋ณธ ์Šคํƒ ํฌ๊ธฐ (20๋ฒˆ์—์„œ ๋‹ค๋ฃธ)
    TPri_Normal              // ์šฐ์„ ์ˆœ์œ„
);

๋‚ด๋ถ€์ ์œผ๋กœ Windows์—์„  _beginthreadex โ†’ CreateThread๋ฅผ ํ˜ธ์ถœ. std::thread์™€ ๊ฑฐ์˜ ๊ฐ™์ง€๋งŒ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ + ๋ผ์ดํ”„์‚ฌ์ดํด ํ›…(Init/Run/Stop/Exit)์ด ํ‘œ์ค€ํ™”๋ผ ์žˆ์Šต๋‹ˆ๋‹ค.

IsInGameThread() โ€” ์•ˆ์ „ ๊ฒ€์ฆ

1
2
3
4
5
void UMyComponent::DoSomething() {
    check(IsInGameThread());  // ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•จ

    MyActor->SetActorLocation(NewLocation);  // UObject ์กฐ์ž‘์€ ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ ์ „์šฉ
}

UObject ์กฐ์ž‘์€ ๊ฒŒ์ž„ ์Šค๋ ˆ๋“œ ์ „์šฉ ์ปจ๋ฒค์…˜. ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ๋งŒ์ง€๋ฉด GC์™€ ์ถฉ๋Œํ•˜๊ฑฐ๋‚˜ race condition์ด ๋‚ฉ๋‹ˆ๋‹ค. check(IsInGameThread())๋Š” ๋””๋ฒ„๊ทธ ๋นŒ๋“œ์—์„œ ์ž˜๋ชป๋œ ์ปจํ…์ŠคํŠธ์—์„œ์˜ ํ˜ธ์ถœ์„ ์ฆ‰์‹œ ์žก์•„์ค๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ์ค„์ด๋Š” ์–ธ๋ฆฌ์–ผ์˜ ํŒจํ„ด

ํŒจํ„ดํšจ๊ณผ
๊ฒŒ์ž„/๋ Œ๋”/RHI ์Šค๋ ˆ๋“œ ๋ถ„๋ฆฌ + ๋ช…๋ น ํ๋™๊ธฐํ™” ๋นˆ๋„ ์ตœ์†Œํ™” โ†’ ๋ฝ ๊ฒฝํ•ฉ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์ ์Œ
TaskGraph + work stealing์›Œ์ปค ํ’€์—์„œ ์ž์ฒด ๋ถ„์‚ฐ โ†’ OS ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ํšŒํ”ผ
ENamedThreads ๋ช…์‹œ์ž˜๋ชป๋œ ์Šค๋ ˆ๋“œ๋กœ ๋””์ŠคํŒจ์น˜ ๋ฐฉ์ง€ โ†’ ์ถ”๊ฐ€ ์Šค์œ„์นญ ํšŒํ”ผ
FCriticalSection (์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ )Windows Critical Section ์ง์ ‘ ๋ž˜ํ•‘ โ€” ๋ฌด๊ฒฝํ•ฉ ์‹œ ๋น ๋ฆ„
TQueue<T, EQueueMode::Mpsc> (lock-free)์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์—†๋Š” ์Šค๋ ˆ๋“œ ๊ฐ„ ํ†ต์‹ 
TLS ํ™œ์šฉ (FThreadSingleton)์Šค๋ ˆ๋“œ๋ณ„ ๋ฐ์ดํ„ฐ โ€” ๋ฝ ์—†์ด ์•ˆ์ „

๊ฒŒ์ž„ ์—”์ง„์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ๋ฏผ๊ฐํ•œ ์ด์œ 

1
2
3
4
5
6
1ํ”„๋ ˆ์ž„ 16.6ms (60fps)
  โ†’ 100ฮผs(์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ 1ํšŒ) ร— 100ํšŒ = 10ms โ† 60% ์†Œ์ง„!
  โ†’ ๊ทธ๋ž˜์„œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ค„์ด๋Š” ๋ชจ๋“  ํŠธ๋ฆญ์„ ๋™์›

๋Œ€์กฐ: ์ผ๋ฐ˜ ์„œ๋ฒ„ ์›Œํฌ๋กœ๋“œ (์š”์ฒญ๋‹น 100ms ์ฒ˜๋ฆฌ)
  โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ 1ms๋Š” 1% ์ •๋„๋ผ ๋ฌด์‹œ ๊ฐ€๋Šฅ

์ด๊ฒŒ ๊ฒŒ์ž„ ์—”์ง„์ด ์ž์ฒด ์ž‘์—… ์‹œ์Šคํ…œ(TaskGraph), ์ž์ฒด ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น๊ธฐ, ์ž์ฒด ๋™๊ธฐํ™” ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์ ๊ทน ๋„์ž…ํ•˜๋Š” ์ง์ ‘์  ์ด์œ ์ž…๋‹ˆ๋‹ค.


17. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ

Q1. โ€œ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ •ํ™•ํžˆ ๋ฌด์—‡์ด๊ณ  ์™œ ํ•„์š”ํ•œ๊ฐ€์š”?โ€

์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ CPU ์ฝ”์–ด ์œ„์—์„œ ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ(๋˜๋Š” ํ”„๋กœ์„ธ์Šค)๋ฅผ ์ž ์‹œ ๋‚ด๋ ค๋†“๊ณ , ๋‹ค๋ฅธ ์‹คํ–‰ ๋‹จ์œ„๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” OS ์ž‘์—…์ž…๋‹ˆ๋‹ค. CPU ์ฝ”์–ด๋Š” ํ•œ ์ˆœ๊ฐ„์— ํ•˜๋‚˜์˜ ๋ช…๋ น ํ๋ฆ„๋งŒ ์‹คํ–‰ํ•˜์ง€๋งŒ OS๋Š” ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๊ฐœ ์Šค๋ ˆ๋“œ๋ฅผ ๋™์‹œ์— ์‚ด์•„์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์—ฌ์ค˜์•ผ ํ•˜๋‹ˆ, ๋น ๋ฅด๊ฒŒ ๋Œ์•„๊ฐ€๋ฉฐ ์‹œ๊ฐ„์„ ์ชผ๊ฐœ ์“ฐ๋Š” ์‹œ๋ถ„ํ• (time-sharing) ๋ชจ๋ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์‹œ๋ถ„ํ• ์˜ ๋ณธ์ฒด๊ฐ€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ž…๋‹ˆ๋‹ค.

๋ฉ”์ปค๋‹ˆ์ฆ˜์€ โ‘  ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ CPU ์ƒํƒœ(๋ ˆ์ง€์Šคํ„ฐยทSPยทPCยทํ”Œ๋ž˜๊ทธ)๋ฅผ ๊ทธ ์Šค๋ ˆ๋“œ์˜ TCB(Thread Control Block, ์Šค๋ ˆ๋“œ ์ œ์–ด ๋ธ”๋ก)์— ์ €์žฅ โ†’ โ‘ก ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‹ค์Œ ์Šค๋ ˆ๋“œ ์„ ํƒ โ†’ โ‘ข ์ƒˆ ์Šค๋ ˆ๋“œ์˜ TCB์—์„œ ์ƒํƒœ ๋ณต์› โ†’ โ‘ฃ ๊ทธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฉˆ์ท„๋˜ ์ž๋ฆฌ๋ถ€ํ„ฐ ์žฌ๊ฐœ. ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค(x86 CR3)๋„ ํ•จ๊ป˜ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.

Q2. โ€œ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ์–ธ์ œ ์ผ์–ด๋‚˜๋‚˜์š”? ์ข…๋ฅ˜๋ฅผ ๋ถ„๋ฅ˜ํ•ด์ฃผ์„ธ์š”.โ€

ํฌ๊ฒŒ ๋„ค ๊ฐ€์ง€ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ(timer interrupt) โ€” OS๊ฐ€ ์Šค๋ ˆ๋“œ์— ํ• ๋‹นํ•œ time slice(quantum, Windows ๊ธฐ๋ณธ ์•ฝ 15.6ms)๊ฐ€ ๋งŒ๋ฃŒ๋˜๋ฉด ํ•˜๋“œ์›จ์–ด ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ๊ฐ•์ œ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ์„ ์ ํ˜•(preemptive) ์Šค์ผ€์ค„๋ง์˜ ๋ณธ์ฒด์ž…๋‹ˆ๋‹ค.
  • ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ โ€” read()ยทrecv()ยทWaitForSingleObject()์ฒ˜๋Ÿผ ๋Œ€๊ธฐ๋ฅผ ๋™๋ฐ˜ํ•˜๋Š” ํ˜ธ์ถœ์„ ๋งŒ๋‚˜๋ฉด ๊ทธ ์Šค๋ ˆ๋“œ๋Š” ์ฆ‰์‹œ Wait ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋””์ŠคํŒจ์น˜๋ฉ๋‹ˆ๋‹ค.
  • ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ โ€” mutexยทsemaphoreยทeventยทcondition variable์—์„œ ์ž ๋“ค๋ฉด ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. Windows์˜ Critical Section์ด๋‚˜ SRWLock์€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์ž ๊น spinํ•˜๋‹ค๊ฐ€ ๊ทธ๋ž˜๋„ ๋ชป ์žก์œผ๋ฉด ๊ทธ๋•Œ ์ปค๋„ ์ง„์ž… โ†’ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ž๋ฐœ์  ์–‘๋ณด โ€” Sleep(0), SwitchToThread, std::this_thread::yield๋กœ ์Šค๋ ˆ๋“œ๊ฐ€ ์ง์ ‘ CPU๋ฅผ ๋‚ด๋ ค๋†“๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ๋Š” ๊ฐ•์ œ, ๋‚˜๋จธ์ง€ ์…‹์€ ์Šค๋ ˆ๋“œ ์ž๋ฐœ์  ํŠธ๋ฆฌ๊ฑฐ์ž…๋‹ˆ๋‹ค.

Q3. โ€œ๋ชจ๋“œ ์Šค์œ„์น˜์™€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ๊ฐ™์€ ๊ฑด๊ฐ€์š”?โ€

๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ชจ๋“œ ์Šค์œ„์น˜(mode switch)๋Š” ๊ฐ™์€ ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ์™€ ์ปค๋„ ๋ชจ๋“œ๋ฅผ ์˜ค๊ฐ€๋Š” ๊ฒƒ์ด๊ณ , ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜(context switch)๋Š” ์‹คํ–‰ ์ฃผ์ฒด(์Šค๋ ˆ๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค)๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ ์ฝœ์ด ์ฆ‰์‹œ ๋๋‚˜๋ฉด(GetCurrentProcessId ๊ฐ™์€ ์ •๋ณด ์กฐํšŒ) ๋ชจ๋“œ ์Šค์œ„์น˜๋งŒ ์ผ์–ด๋‚˜๊ณ  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ์—†์Šต๋‹ˆ๋‹ค โ€” ๊ฐ™์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉ์ž ๋ชจ๋“œ๋กœ ๋Œ์•„์˜ต๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋Š” ๋ณดํ†ต ๋ชจ๋“œ ์Šค์œ„์น˜ ์œ„์—์„œ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค โ€” ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ์ปค๋„ ๋ชจ๋“œ ์ง„์ž… โ†’ ์Šค์ผ€์ค„๋Ÿฌ โ†’ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ๊ฐˆ์•„๋ผ์›€ โ†’ ๋‹ค์‹œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ.

์˜ˆ์™ธ๊ฐ€ Fiber์ธ๋ฐ, SwitchToFiber๋Š” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ SPยทPC๋ฅผ ์ง์ ‘ ๋ฐ”๊ฟ”์น˜๊ธฐํ•˜๋ฏ€๋กœ ๋ชจ๋“œ ์Šค์œ„์น˜๋„ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์ˆ˜์‹ญ nanosecond์— ๋๋‚ฉ๋‹ˆ๋‹ค.

Q4. โ€œ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์˜ ๋น„์šฉ ์š”์†Œ๋ฅผ ์ž์„ธํžˆ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.โ€

๋น„์šฉ์€ ์—ฌ๋Ÿฌ ์ธต์—์„œ ๋ˆ„์ ๋ฉ๋‹ˆ๋‹ค. ๋ถ„๋ฆฌํ•ด์„œ ๋ณด๋ฉด:

  • ๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์› โ€” ์ง์ ‘ ๋น„์šฉ. x86_64๋ฉด GPR 16๊ฐœ + ํ”Œ๋ž˜๊ทธ + (์„ ํƒ์ ) FPU/SIMD๋ฅผ ๋ฉ”๋ชจ๋ฆฌ(TCB)๋กœ ์˜ฎ๊ธฐ๊ณ  ๋‹ค์‹œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋ณดํ†ต ์ˆ˜๋ฐฑ nanosecond.
  • ์บ์‹œ ์ฝœ๋“œ(cache cold) โ€” ๊ฐ€์žฅ ํฐ ๊ฐ„์ ‘ ๋น„์šฉ. ์ƒˆ ์Šค๋ ˆ๋“œ์˜ ๋ฐ์ดํ„ฐยท๋ช…๋ น์–ด๊ฐ€ L1ยทL2 ์บ์‹œ์— ์—†์–ด ์ง„์ž… ์งํ›„ ์ค„์ค„์ด ์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ๋น„์šฉ๋ณด๋‹ค ์ˆ˜~์ˆ˜์‹ญ ๋ฐฐ ํด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • TLB(Translation Lookaside Buffer, ์ฃผ์†Œ ๋ณ€ํ™˜ ์บ์‹œ) flush โ€” ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์—์„œ๋งŒ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์ด ๋ฐ”๋€Œ๋ฏ€๋กœ MMU(Memory Management Unit)๊ฐ€ ์บ์‹ฑํ•˜๋˜ ๊ฐ€์ƒโ†’๋ฌผ๋ฆฌ ๋งคํ•‘์„ ๋น„์›๋‹ˆ๋‹ค. ์ดํ›„ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ๋งˆ๋‹ค ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ๊ฐ€ ๋‹ค์‹œ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  • ํŒŒ์ดํ”„๋ผ์ธ ์ •์ง€์™€ ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ ๋ฌดํšจํ™” โ€” instruction pipeline์˜ ๋ช…๋ น๋“ค์ด ํ๊ธฐ๋˜๊ณ , ๋ถ„๊ธฐ ์˜ˆ์ธก๊ธฐ ํ•™์Šต์ด ์–ด๊ธ‹๋‚ฉ๋‹ˆ๋‹ค.
  • ์ปค๋„ ์ง„์ž…(๋ชจ๋“œ ์Šค์œ„์น˜) ์ž์ฒด ๋น„์šฉ โ€” ๋ณดํ†ต 100~500 nanosecond. Spectre/Meltdown ์™„ํ™” ํŒจ์น˜(KPTI) ์ดํ›„์—” ๋” ๋น„์‹ธ์กŒ์Šต๋‹ˆ๋‹ค.

์ดํ•ฉ์œผ๋กœ ์Šค๋ ˆ๋“œ ์ „ํ™˜์€ ์•ฝ 1~5ฮผs, ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์€ 5~20ฮผs ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค.

Q5. โ€œํ”„๋กœ์„ธ์Šค ์ „ํ™˜๊ณผ ์Šค๋ ˆ๋“œ ์ „ํ™˜์˜ ๋น„์šฉ ์ฐจ์ด๋Š” ์™œ 5~10๋ฐฐ๊ฐ€ ๋‚˜๋‚˜์š”?โ€

ํ•ต์‹ฌ์€ TLB flush์™€ ์บ์‹œ ์ฝœ๋“œ์ž…๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ์ „ํ™˜์€ ๊ฐ™์€ PCB(๊ฐ™์€ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„) ์•ˆ์—์„œ TCB๋งŒ ๋ฐ”๊พธ๋ฏ€๋กœ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ฒ ์ด์Šค ๋ ˆ์ง€์Šคํ„ฐ(x86 CR3)๋ฅผ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  TLBยทํ•ธ๋“ค ํ…Œ์ด๋ธ”ยท๋ฉ”๋ชจ๋ฆฌ๋งต์ด ๋ณด์กด๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์งํ›„ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ์ผ๋ฐ˜ ์†๋„๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์€ CR3๋ฅผ ๊ต์ฒดํ•˜๊ณ  TLB๋ฅผ ๋น„์›Œ์•ผ ํ•˜๋‹ˆ, ์งํ›„ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด TLB miss๋กœ ์‹œ์ž‘ํ•ด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์›Œํฌ(4๋‹จ๊ณ„ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์ด๋ฉด 4๋ฒˆ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ)๋ฅผ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๋„ working set ์ž์ฒด๊ฐ€ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค ๊ฒƒ์ด๋ผ ์ง„์ž… ์งํ›„ ๊ฑฐ์˜ ๋ชจ๋‘ ๋ฏธ์Šค๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋งŒ ํ˜„๋Œ€ x86์€ PCID(Process Context ID), ARM์€ ASID(Address Space ID)๋กœ TLB ์—”ํŠธ๋ฆฌ์— ํ”„๋กœ์„ธ์Šค ID๋ฅผ ํƒœ๊น…ํ•ด์„œ ์ „์ฒด flush๋ฅผ ํšŒํ”ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ์บ์‹œ ์ฝœ๋“œ๋Š” ํšŒํ”ผ ๋ชป ํ•ด์„œ ์ฐจ์ด๋Š” ์—ฌ์ „ํžˆ ํฝ๋‹ˆ๋‹ค.

Q6. โ€œ์Šค์ผ€์ค„๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ์–ด๋–ป๊ฒŒ ์˜ํ–ฅ์„ ์ฃผ๋‚˜์š”?โ€

์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์˜ ๋นˆ๋„์™€ ์ •์ฑ…์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

์„ ์ ํ˜•(preemptive) ์Šค์ผ€์ค„๋ง์€ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋กœ ๊ฐ•์ œ ์Šค์œ„์นญ์„ ์ผ์œผํ‚ค๋Š” ๋ชจ๋ธ๋กœ WindowsยทLinux์˜ ํ‘œ์ค€์ž…๋‹ˆ๋‹ค. quantum์ด ์งง์œผ๋ฉด(์˜ˆ: 1ms) ์‘๋‹ต์„ฑ์€ ์ข‹์ง€๋งŒ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋นˆ๋„๊ฐ€ ๋Š˜์–ด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ˆ„์ ๋˜๊ณ , ๊ธธ๋ฉด(100ms+) throughput์€ ์ข‹์ง€๋งŒ ์‘๋‹ต์„ฑ์ด ๋‚˜๋น ์ง‘๋‹ˆ๋‹ค โ€” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„์ž…๋‹ˆ๋‹ค. Windows ๊ธฐ๋ณธ quantum์€ ์•ฝ 15.6ms์ž…๋‹ˆ๋‹ค.

๋น„์„ ์ ํ˜•/ํ˜‘๋ ฅ์ (cooperative) ์Šค์ผ€์ค„๋ง์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž๋ฐœ์ ์œผ๋กœ ์–‘๋ณดํ•  ๋•Œ๋งŒ ์Šค์œ„์นญํ•˜๋Š” ๋ชจ๋ธ๋กœ, Fiber์™€ ์ฝ”๋ฃจํ‹ด์ด ์ด ํŒจ๋Ÿฌ๋‹ค์ž„์ž…๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ ์ง€๋งŒ ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์–‘๋ณด๋ฅผ ์•ˆ ํ•˜๋ฉด ์‹œ์Šคํ…œ์ด ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.

์•Œ๊ณ ๋ฆฌ์ฆ˜๋ณ„๋กœ๋Š” Round-Robin(๊ท ๋“ฑ quantum), ์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง(๋†’์€ ์šฐ์„ ์ˆœ์œ„ ๋จผ์ €, ๊ธฐ์•„ ์œ„ํ—˜), MLFQ(Multi-Level Feedback Queue) (ํ–‰๋™ ํŒจํ„ด์œผ๋กœ ์ž๋™ ๋ถ„๋ฅ˜) ๋“ฑ์ด ์žˆ๊ณ , WindowsยทLinux๋Š” MLFQ์— ๊ฐ€๊นŒ์šด dynamic priority ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Q7. โ€œWindows์—์„œ ๋™๊ธฐํ™” ๊ฐ์ฒด๋ณ„ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์š”?โ€

์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ ์ด๋ƒ, ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…์ด๋ƒ๊ฐ€ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.

  • std::atomic โ€” CPU ๋ช…๋ น(LOCK XADD ๋“ฑ)์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆ˜ nanosecond.
  • Critical Section / SRWLock โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์งง๊ฒŒ spin โ†’ ๊ทธ๋ž˜๋„ ๋ชป ์žก์œผ๋ฉด ๊ทธ๋•Œ ์ปค๋„ ์ง„์ž…. ๋ฌด๊ฒฝํ•ฉ ์ผ€์ด์Šค์—์„  50~100 nanosecond. ๋‹จ, ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. SRWLock์€ R/W ๋ถ„๋ฆฌ.
  • Condition Variable โ€” SleepConditionVariableSRW๋กœ ๊ตฌํ˜„๋˜์–ด ์‚ฌ์šฉ์ž ๋ชจ๋“œ ์šฐ์„ .
  • Mutex / Event / Semaphore โ€” ์ปค๋„ ๊ฐ์ฒด๋ผ ํ•ญ์ƒ ์ปค๋„ ์ง„์ž…. ๋ฌด๊ฒฝํ•ฉ์ด๋ผ๋„ 1~3 microsecond. ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ  ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒŒ ์žฅ์ .

MSVC์˜ std::mutex๋Š” SRWLock ์œ„์— ๊ตฌํ˜„๋ผ ์žˆ์–ด ๋ฌด๊ฒฝํ•ฉ ์‹œ ๊ฑฐ์˜ ๋น„์šฉ์ด ์—†๊ณ , Mutex์˜ 20~50๋ฐฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์˜ ๋™๊ธฐํ™”๋Š” Critical Section/SRWLock, ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งŒ Mutex๊ฐ€ ์ปจ๋ฒค์…˜์ž…๋‹ˆ๋‹ค.

Q8. โ€œConcurrency Runtime / PPL์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์–ด๋–ป๊ฒŒ ์ค„์ด๋‚˜์š”?โ€

ConcRT๋Š” OS ์œ„์— ์‚ฌ์šฉ์ž ๋ชจ๋“œ Task Scheduler๋ฅผ ๋‘์–ด OS ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ค„์ด๋Š” MSVC์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค(/cpp/parallel/concrt/). ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์„ธ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

์ฒซ์งธ work stealing โ€” ๊ฐ ์›Œ์ปค๊ฐ€ ์ž๊ธฐ ์ž‘์—… ํ๋ฅผ ๊ฐ€์ง€๊ณ , ํ•œ๊ฐ€ํ•œ ์›Œ์ปค๊ฐ€ ๋‹ค๋ฅธ ์›Œ์ปค์˜ ํ ๋์—์„œ ์ž‘์—…์„ ํ›”์ณ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ฝ ๊ฒฝํ•ฉ ์—†์ด ๋ถ€ํ•˜ ๋ถ„์‚ฐ์ด ์ผ์–ด๋‚˜ OS ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๊ฑฐ์˜ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‘˜์งธ Context::Block/Yield/Unblock โ€” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์ž‘์—… ์ปจํ…์ŠคํŠธ๋ฅผ ์–‘๋ณดยท๋ธ”๋กยท์žฌ๊ฐœํ•˜๋Š” API. OS๊ฐ€ ๋ชจ๋ฅด๋Š” ํ˜‘๋ ฅ์  ์Šค์ผ€์ค„๋ง์ด๋ผ ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ nanosecond์— ๋๋‚ฉ๋‹ˆ๋‹ค.

์…‹์งธ oversubscription โ€” ๋ธ”๋กœํ‚น ํ˜ธ์ถœ ์ง์ „์— Oversubscribe(true)๋กœ ์ž„์‹œ ์ถ”๊ฐ€ ์›Œ์ปค๋ฅผ ๋„์›Œ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

PPL์˜ parallel_forยทparallel_invokeยทtask<T>๊ฐ€ ๊ทธ ์œ„์— ์–นํžŒ ๊ณ ์ˆ˜์ค€ API๋กœ, 1000๊ฐœ ๋ฐ˜๋ณต์„ OS ์Šค๋ ˆ๋“œ 1000๊ฐœ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋Œ€์‹  ์ฝ”์–ด ์ˆ˜๋งŒํผ์˜ ํ’€์—์„œ work stealing์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๊ทน์ ์œผ๋กœ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

Q9. โ€œFiber์™€ OS ์Šค๋ ˆ๋“œ์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์ฐจ์ด๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?โ€

Fiber๋Š” ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ๋งŒ ๊ด€๋ฆฌ๋˜๋Š” ํ˜‘๋ ฅ์  ์‹คํ–‰ ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. OS ์ปค๋„์€ Fiber๋ฅผ ๋ชจ๋ฅด๊ณ , ํ•œ OS ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์—ฌ๋Ÿฌ Fiber๊ฐ€ ์ž๊ธฐ๋“ค๋ผ๋ฆฌ SPยทPC๋ฅผ ๋ฐ”๊ฟ”์น˜๊ธฐํ•ฉ๋‹ˆ๋‹ค. SwitchToFiber ํ˜ธ์ถœ์€ ์ˆ˜์‹ญ nanosecond๋กœ OS ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜(1~5ฮผs)์˜ 50๋ฐฐ ์ด์ƒ ๋น ๋ฆ…๋‹ˆ๋‹ค.

๋‹จ์ ์ด ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ™œ์šฉ ๋ถˆ๊ฐ€ โ€” ํ•œ OS ์Šค๋ ˆ๋“œ ์•ˆ์˜ Fiber๋“ค์ด๋ผ ์ฝ”์–ด ํ•˜๋‚˜์—์„œ๋งŒ ๋•๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์ฝœ ๋ธ”๋กœํ‚น ์‹œ ํ˜ธ์ŠคํŠธ ์Šค๋ ˆ๋“œ ์ „์ฒด ๋ฉˆ์ถค โ€” OS๊ฐ€ Fiber๋ฅผ ๋ชจ๋ฅด๋‹ˆ ๊ทธ ์•ˆ์˜ ๋‹ค๋ฅธ Fiber๋“ค๋„ ๊ฐ™์ด ๋ฉˆ์ถฅ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ˆœ์ˆ˜ CPU-bound ์ž‘์—…์— ์ ํ•ฉํ•˜๊ณ , I/O์™€ ์„ž์ด๋ฉด ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค.

Naughty Dog์˜ ๊ฒŒ์ž„ ์—”์ง„ ์ž‘์—… ์‹œ์Šคํ…œ์ด OS ์Šค๋ ˆ๋“œ ํ’€ + Fiber ์กฐํ•ฉ์œผ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ๊ทน๋‹จ์ ์œผ๋กœ ์ค„์ธ ์œ ๋ช… ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ํ˜„๋Œ€ C++์—์„  ์ฝ”๋ฃจํ‹ด(C++20)์ด ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€์•ˆ์ด ๋์Šต๋‹ˆ๋‹ค.

์ ˆ์ถฉ ๋ชจ๋ธ์ธ UMS(User-Mode Scheduling) ๋Š” ์ปค๋„์ด ์Šค๋ ˆ๋“œ๋ฅผ ์•Œ๋ฉด์„œ ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ ์Šค์ผ€์ค„๋งํ•˜๋Š” Windows 7+ x64 ๊ธฐ๋Šฅ์œผ๋กœ, Fiber์˜ ํ•œ๊ณ„๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค ํ–ˆ์ง€๋งŒ ์‚ฌ์šฉ ๋ณต์žก๋„ ๋•Œ๋ฌธ์— ์ฑ„ํƒ๋ฅ ์ด ๋‚ฎ์Šต๋‹ˆ๋‹ค.

Q10. โ€œC++์˜ std::thread, std::mutex๊ฐ€ Windows์—์„  ์–ด๋–ป๊ฒŒ ๋งคํ•‘๋˜๊ณ , TLS์™€ CRT๊ฐ€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?โ€

๋งคํ•‘๋ถ€ํ„ฐ ๋ณด๋ฉด, std::thread ๋Š” MSVC์—์„œ _beginthreadex โ†’ CreateThread๋กœ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค. _beginthreadex๋ฅผ ๊ฑฐ์น˜๋Š” ์ด์œ ๋Š” CRT์˜ TLS ์ดˆ๊ธฐํ™”(stdio ๋ฝ, errno, strtok ๋“ฑ)๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค โ€” raw CreateThread๋ฅผ ์ง์ ‘ ์“ฐ๋ฉด CRT ํ•จ์ˆ˜๊ฐ€ ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

std::mutex ๋Š” Visual Studio 2019 16.x ์ดํ›„ SRWLock ์œ„์— ๊ตฌํ˜„๋ผ ์žˆ์–ด ๋ฌด๊ฒฝํ•ฉ ์ผ€์ด์Šค์—์„  ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. std::shared_mutex ๋„ SRWLock์˜ R/W ๋ถ„๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ๋…ธ์ถœ. std::condition_variable ์€ Windows Condition Variable. std::atomic ์€ CPU ๋ช…๋ น์œผ๋กœ ์ง์ ‘ ๋งคํ•‘๋˜์–ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ์ž์ฒด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

TLS(Thread Local Storage) ๋Š” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์— ์˜ํ–ฅ์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. TLS ๋ณ€์ˆ˜๋Š” ์Šค๋ ˆ๋“œ ์ž๊ธฐ ๋ฉ”๋ชจ๋ฆฌ(TCB๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์˜์—ญ)์— ์ƒ์ฃผํ•˜๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ gs:[...] ์„ธ๊ทธ๋จผํŠธ ๋ ˆ์ง€์Šคํ„ฐ ๊ธฐ์ค€์œผ๋กœ ์ ‘๊ทผํ•˜๊ธฐ ๋•Œ๋ฌธ์— OS๊ฐ€ ๋”ฐ๋กœ ์ €์žฅยท๋ณต์›ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค โ€” TCB๊ฐ€ ์ƒˆ ์Šค๋ ˆ๋“œ ๊ฒƒ์œผ๋กœ ๋ฐ”๋€Œ๋ฉด ์ž๋™์œผ๋กœ ์ƒˆ TLS๋ฅผ ์ฐพ์•„๊ฐ‘๋‹ˆ๋‹ค. __declspec(thread)(MSVC) ๋˜๋Š” thread_local(C++11)์ด ์ปจ๋ฒค์…˜์ž…๋‹ˆ๋‹ค.

CRT ์˜ต์…˜์€ ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ์˜ํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. /MT(์ •์  CRT)์™€ /MD(DLL CRT)๋Š” ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์˜ ๋ชจ๋“ˆ๋“ค์ด ๊ฐ™์€ CRT ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๋А๋ƒ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ , CRT ๋‚ด๋ถ€์—๋Š” stdio ๋ฝ, ํž™ ๋ฝ, static ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” ๋ฝ์ด ์žˆ์–ด ์ด๊ฒŒ ์˜๋„์น˜ ์•Š์€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งค ํ”„๋ ˆ์ž„ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ printf๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด stdio ๋ฝ ๊ฒฝํ•ฉ์œผ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒŒ ๋Œ€ํ‘œ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค โ€” ๊ฒŒ์ž„/์„œ๋ฒ„์—์„œ ์ž์ฒด lock-free ๋กœ๊น…์„ ์“ฐ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. MSVC ๋ฌธ์„œ๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ /MD + _beginthreadex ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋Š” ์ด์œ ๊ฐ€ ์ด๋Ÿฐ ๋ฉ”๋ชจ๋ฆฌยท๋ฝ ์ผ๊ด€์„ฑ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


18. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ (์žฌ๊ฒŒ์žฌ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ = CPU ์ฝ”์–ด์—์„œ ์‹คํ–‰๋˜๋˜ ์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” OS ์ž‘์—….
                  ํ˜„์žฌ ์ปจํ…์ŠคํŠธ(๋ ˆ์ง€์Šคํ„ฐยทSPยทPC) โ†’ PCB/TCB ์ €์žฅ โ†’ ๋‹ค์Œ ์ปจํ…์ŠคํŠธ ๋ณต์›.

๋ฐœ์ƒ ์‹œ์  4๊ฐ€์ง€:
  โ‘  ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ โ€” quantum ๋งŒ๋ฃŒ (์„ ์ ํ˜•)
  โ‘ก ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ โ€” read/recv/WaitForSingleObject
  โ‘ข ๋™๊ธฐํ™” ๊ฐ์ฒด ๋Œ€๊ธฐ โ€” mutex/event/condition variable
  โ‘ฃ ์ž๋ฐœ์  ์–‘๋ณด โ€” Sleep(0)/SwitchToThread/std::this_thread::yield

๋น„์šฉ ์š”์†Œ:
  โ‘  ๋ ˆ์ง€์Šคํ„ฐ ์ €์žฅยท๋ณต์›       โ€” ์ง์ ‘, ์ˆ˜๋ฐฑ ns
  โ‘ก ์บ์‹œ ์ฝœ๋“œ (cache cold)   โ€” ๊ฐ„์ ‘, ๊ฐ€์žฅ ํผ (์ˆ˜~์ˆ˜์‹ญ ฮผs)
  โ‘ข TLB flush                โ€” ํ”„๋กœ์„ธ์Šค ์ „ํ™˜๋งŒ (PCID/ASID๋กœ ํšŒํ”ผ ๊ฐ€๋Šฅ)
  โ‘ฃ ํŒŒ์ดํ”„๋ผ์ธยท๋ถ„๊ธฐ ์˜ˆ์ธก ๋ฌดํšจํ™”
  โ‘ค ์ปค๋„ ์ง„์ž… ์ž์ฒด (๋ชจ๋“œ ์Šค์œ„์น˜)

ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ vs ์Šค๋ ˆ๋“œ ์ „ํ™˜:
  ์Šค๋ ˆ๋“œ = TCB๋งŒ ๊ต์ฒด, ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ๋ณด์กด โ†’ 1~5 ฮผs
  ํ”„๋กœ์„ธ์Šค = CR3 ๊ต์ฒด + TLB flush + ์บ์‹œ ์ฝœ๋“œ โ†’ 5~20 ฮผs
  โ†’ 5~10๋ฐฐ ์ฐจ์ด (19๋ฒˆ ํšŒ๊ท€)

๋ชจ๋“œ ์Šค์œ„์น˜ โ‰  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜:
  ๋ชจ๋“œ ์Šค์œ„์น˜ = ๊ฐ™์€ ์Šค๋ ˆ๋“œ user โ†” kernel (PCB ๊ต์ฒด ์—†์Œ)
  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ = ์‹คํ–‰ ์ฃผ์ฒด ๊ต์ฒด

์Šค์ผ€์ค„๋ง:
  ์„ ์ ํ˜• (WindowsยทLinux ํ‘œ์ค€)  vs  ํ˜‘๋ ฅ์  (Fiberยท์ฝ”๋ฃจํ‹ด)
  Round-Robin / ์šฐ์„ ์ˆœ์œ„ / MLFQ
  Windows quantum ๊ธฐ๋ณธ ~15.6ms, timeBeginPeriod(1)๋กœ 1ms๊นŒ์ง€

Windows ๋น„์šฉ ์ŠคํŽ™ํŠธ๋Ÿผ (๋‚ฎ์Œ โ†’ ๋†’์Œ):
  std::atomic                    ์ˆ˜ ns          (์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์Œ)
  Fiber SwitchToFiber            ์ˆ˜์‹ญ ns        (์‚ฌ์šฉ์ž ๋ชจ๋“œ, ๋ฉ€ํ‹ฐ์ฝ”์–ด X)
  ConcRT Context::Yield          ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ ns   (์‚ฌ์šฉ์ž ๋ชจ๋“œ ํ˜‘๋ ฅ์ )
  Critical Section / SRWLock     50~100 ns ๋ฌด๊ฒฝํ•ฉ (์‚ฌ์šฉ์ž ์šฐ์„ , ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋งŒ)
  Condition Variable             ๋น„์Šท            (์‚ฌ์šฉ์ž ์šฐ์„ )
  Mutex / Event / Semaphore      1~3 ฮผs         (ํ•ญ์ƒ ์ปค๋„, ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ  ๊ฐ€๋Šฅ)
  OS ์Šค๋ ˆ๋“œ quantum ๋งŒ๋ฃŒ          1~5 ฮผs         (์Šค๋ ˆ๋“œ ์ „ํ™˜)
  OS ํ”„๋กœ์„ธ์Šค ์ „ํ™˜                5~20 ฮผs        (TLB flush ํฌํ•จ)

C++ ํ‘œ์ค€ โ†’ Windows ๋งคํ•‘:
  std::thread          โ†’ _beginthreadex โ†’ CreateThread
  std::mutex           โ†’ SRWLock (VS 2019 16.x+)
  std::shared_mutex    โ†’ SRWLock (R/W)
  std::condition_var   โ†’ Windows Condition Variable
  std::atomic          โ†’ CPU ๋ช…๋ น (LOCK XADD ๋“ฑ)
  std::async           โ†’ ThreadPool API or ์ƒˆ ์Šค๋ ˆ๋“œ

TLS:
  __declspec(thread) / thread_local โ†’ ์Šค๋ ˆ๋“œ ์ž๊ธฐ ๋ฉ”๋ชจ๋ฆฌ ์ƒ์ฃผ
  ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์‹œ ์ž๋™ ๋ณด์กด (gs:[...] ์„ธ๊ทธ๋จผํŠธ ๋ฒ ์ด์Šค ๊ต์ฒด)
  TlsAlloc/TlsGetValue๋กœ ๋™์  ์Šฌ๋กฏ๋„ ๊ฐ€๋Šฅ

CRT ์˜ต์…˜:
  /MT  ์ •์  CRT  โ€” ๋‹จ๋… EXE, ์ธ์Šคํ„ด์Šค ๋ถ„๋ฆฌ (์œ„ํ—˜)
  /MD  DLL CRT   โ€” ๊ถŒ์žฅ (UCRT, ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋ชจ๋“ˆ ์ธ์Šคํ„ด์Šค ๊ณต์œ )
  ๋‚ด๋ถ€ ๋ฝ: stdioยทheapยทstatic init โ†’ ์˜๋„์น˜ ์•Š์€ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์œ ๋ฐœ

์–ธ๋ฆฌ์–ผ:
  GameThread / RenderThread / RHIThread ๋ถ„๋ฆฌ + ๋ช…๋ น ํ
  TaskGraph + work stealing (์‚ฌ์šฉ์ž ๋ชจ๋“œ)
  ENamedThreads ๋ช…์‹œ (GameThread, AnyBackgroundThreadNormalTask)
  FRunnableThread (CreateThread ๋ž˜ํ•‘) / FCriticalSection (Critical Section)
  TQueue<T, EQueueMode::Mpsc> (lock-free)
  IsInGameThread() / check() โ€” ์•ˆ์ „ ๊ฒ€์ฆ

๊ธฐ์–ตํ•  ํ•œ ์ค„:
  "์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ํ”ผํ•  ์ˆ˜ ์—†๋Š” OS ๋ฉ”์ปค๋‹ˆ์ฆ˜, ์—”์ง€๋‹ˆ์–ด๋ง์€ ๋นˆ๋„์™€ ๋น„์šฉ์„ ์ค„์ด๋Š” ๋ฐฉํ–ฅ."

19. ํšŒ๊ท€ ๋‹ค๋ฆฌ โ€” ๋‹ค๋ฅธ CS ํŒŒ์ผ ์—ฐ๊ฒฐ

ํŒŒ์ผ์—ฐ๊ฒฐ ์ง€์ 
01_runtime๋ฉ”๋ชจ๋ฆฌ 4์˜์—ญ(Code/Data/Heap/Stack) โ€” ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”ยทTLBยท์บ์‹œ์˜ ํ† ๋Œ€. ํ”„๋กœ์„ธ์Šค ์ „ํ™˜ ์‹œ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„ ๊ต์ฒด์˜ ์ถœ๋ฐœ์ 
03_new_vs_mallocํž™ ๋ฝ(malloc/new ๋‚ด๋ถ€)์ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์œ ๋ฐœ ๊ฐ€๋Šฅ โ€” mimalloc/tcmalloc ๊ฐ™์€ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์นœํ™” ํ• ๋‹น๊ธฐ๋กœ ํšŒํ”ผ
09_rtti_raiistd::lock_guard/std::unique_lock์ด RAII๋กœ ๋ฝ ์ž๋™ ๊ด€๋ฆฌ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ํ›„ unlock ๋ˆ„๋ฝ ๋ฐฉ์ง€
11_smart_pointershared_ptr ์ œ์–ด ๋ธ”๋ก์˜ atomic ์นด์šดํ„ฐ โ€” ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์—†์ด ์•ˆ์ „ํ•œ ์ฐธ์กฐ ์นด์šดํŒ…
16_stl_containersSTL ์ปจํ…Œ์ด๋„ˆ thread-safety ์ปจ๋ฒค์…˜ โ€” ์™ธ๋ถ€ mutex ๋˜๋Š” lock-free ์ปจํ…Œ์ด๋„ˆ๋กœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ์ œ์–ด
19_process_vs_thread์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์ด 19๋ฒˆ์˜ ํ•ต์‹ฌ ๋น„๊ต ํ•ญ๋ชฉ โ€” 21๋ฒˆ์—์„œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊นŠ์ด ํ™•์žฅ. PCB/TCBยทTLBยทCR3 ๊ฐœ๋… ์ง์ ‘ ํšŒ๊ท€
20_stack_overflow์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ ์Šคํƒ + SP๊ฐ€ ์ปจํ…์ŠคํŠธ์˜ ํ•ต์‹ฌ ๊ตฌ์„ฑ์š”์†Œ โ€” 20๋ฒˆ์—์„œ ๋‹ค๋ฃฌ ์Šคํƒ ํ•œ๊ณ„์™€ ์ปจํ…์ŠคํŠธ ๋ณด์กด์ด ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‹ค๋ฃธ
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

ยฉ GoldBoll. ์ผ๋ถ€ ๊ถŒ๋ฆฌ ๋ณด์œ 

Powered by Jekyll with Chirpy theme

์ธ๊ธฐ ํƒœ๊ทธ