๐Ÿš€ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ: C++ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์˜ ์ˆจ๊ฒจ์ง„ ๋น„๋ฐ€ ํŒŒํ—ค์น˜๊ธฐ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ: C++ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์˜ ์ˆจ๊ฒจ์ง„ ๋น„๋ฐ€ ํŒŒํ—ค์น˜๊ธฐ

 

 

์•ˆ๋…•, ์ฝ”๋”ฉ ์นœ๊ตฌ๋“ค! ์˜ค๋Š˜์€ 2025๋…„ 3์›” 18์ผ, C++ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์‹ฌ์žฅ๋ถ€๋กœ ํ•จ๊ป˜ ์—ฌํ–‰์„ ๋– ๋‚˜๋ณผ๊นŒ? ๐Ÿงญ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์ด๋ผ๋Š” ์ฃผ์ œ๊ฐ€ ์–ด๋ ต๊ฒŒ ๋“ค๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๊ฑฑ์ • ๋งˆ! ๋งˆ์น˜ ์นœ๊ตฌ์™€ ์ˆ˜๋‹ค ๋–จ๋“ฏ์ด ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ์„ค๋ช…ํ•ด์ค„๊ฒŒ. ์ด ์ง€์‹์€ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด์ž, ๊ณ ์„ฑ๋Šฅ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๋น„๋ฐ€ ๋ฌด๊ธฐ์•ผ! ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์‹ค๋ ฅ์„ ๋‚˜๋ˆ„๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๊ผญ ์•Œ์•„์•ผ ํ•  ๋‚ด์šฉ์ด๋‹ˆ ๋๊นŒ์ง€ ํ•จ๊ป˜ ํ•ด๋ณด์ž! ๐Ÿค“

๐Ÿ“š ๋ชฉ์ฐจ

  1. ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๊ธฐ์ดˆ: ์ปดํ“จํ„ฐ๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ๋ฐฉ๋ฒ•
  2. C++11 ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์†Œ๊ฐœ: ๊ฒŒ์ž„์˜ ๊ทœ์น™์ด ๋ฐ”๋€Œ์—ˆ๋‹ค!
  3. ์›์ž์  ์—ฐ์‚ฐ์˜ ๋งˆ๋ฒ•: ๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ์ตœ์†Œ ๋‹จ์œ„
  4. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ(Memory Ordering): ์ปดํ“จํ„ฐ์˜ ์ƒ๊ฐ ์ˆœ์„œ ์กฐ์ ˆํ•˜๊ธฐ
  5. ์‹ค์ „ ์˜ˆ์ œ: ์ฝ”๋“œ๋กœ ๋ณด๋Š” ์›์ž์  ์—ฐ์‚ฐ
  6. ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด: ์ตœ์ ์˜ ๊ท ํ˜• ์ฐพ๊ธฐ
  7. ๋””๋ฒ„๊น… ํŒ: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ
  8. ๋ฏธ๋ž˜ ์ „๋ง: C++23๊ณผ ๊ทธ ์ดํ›„

1. ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๊ธฐ์ดˆ: ์ปดํ“จํ„ฐ๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ๋ฐฉ๋ฒ• ๐Ÿง 

์ปดํ“จํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ๋Œ€ํ•œ ์ฐฝ๊ณ ๋ผ๊ณ  ์ƒ์ƒํ•ด๋ด. ์ด ์ฐฝ๊ณ ์—๋Š” ์ˆ˜๋งŽ์€ ์„ ๋ฐ˜(๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ)์ด ์žˆ๊ณ , ๊ฐ ์„ ๋ฐ˜์—๋Š” ๋ฌผ๊ฑด(๋ฐ์ดํ„ฐ)์ด ๋†“์—ฌ ์žˆ์–ด. ๋‹จ์ผ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ์ฐฝ๊ณ  ๊ด€๋ฆฌ์ž๊ฐ€ ํ•œ ๋ช…๋ฟ์ด๋ผ ๋ชจ๋“  ๊ฒŒ ์งˆ์„œ์ •์—ฐํ•˜๊ฒŒ ์ง„ํ–‰๋ผ. ํ•˜์ง€๋งŒ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์€ ์—ฌ๋Ÿฌ ๊ด€๋ฆฌ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ฐฝ๊ณ ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„. ์ด๋Ÿด ๋•Œ ํ˜ผ๋ž€์ด ์ƒ๊ธฐ์ง€ ์•Š์œผ๋ ค๋ฉด ํŠน๋ณ„ํ•œ ๊ทœ์น™์ด ํ•„์š”ํ•˜์ง€! ๐Ÿข

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์ด๋ž€? ๐Ÿค”

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์€ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฉ”๋ชจ๋ฆฌ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ •์˜ํ•˜๋Š” ๊ทœ์น™์˜ ์ง‘ํ•ฉ์ด์•ผ. ์ด ๊ทœ์น™๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ์— ๋‹ตํ•ด์ค˜:

  1. ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•  ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ?
  2. ํ•œ ์Šค๋ ˆ๋“œ์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ ์–ธ์ œ ๋ณด์ด๊ฒŒ ๋ ๊นŒ?
  3. ์ปดํŒŒ์ผ๋Ÿฌ์™€ CPU๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•  ๋•Œ ์–ด๋–ค ๊ฐ€์ •์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

C++์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ์ดํ•ดํ•˜๊ธฐ ์ „์—, ๋จผ์ € ์ปดํ“จํ„ฐ ํ•˜๋“œ์›จ์–ด๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž. ํ˜„๋Œ€ ์ปดํ“จํ„ฐ๋Š” CPU, ์บ์‹œ, ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ๋ผ๋Š” ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์–ด. ๐Ÿ–ฅ๏ธ

CPU ์ฝ”์–ด 1 CPU ์ฝ”์–ด 2 L1/L2 ์บ์‹œ L1/L2 ์บ์‹œ ๊ณต์œ  L3 ์บ์‹œ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ ํ˜„๋Œ€ ์ปดํ“จํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ

์ด ๊ตฌ์กฐ์—์„œ ์ค‘์š”ํ•œ ์ ์€ ๊ฐ CPU ์ฝ”์–ด๊ฐ€ ์ž์‹ ๋งŒ์˜ ์บ์‹œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฑฐ์•ผ. ๊ทธ๋ž˜์„œ ํ•œ ์ฝ”์–ด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด๋„ ๋‹ค๋ฅธ ์ฝ”์–ด๋Š” ์ž๊ธฐ ์บ์‹œ์— ์žˆ๋Š” ์˜ค๋ž˜๋œ ๊ฐ’์„ ๊ณ„์† ๋ณด๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์–ด. ์ด๋Ÿฐ ํ˜„์ƒ์„ '์บ์‹œ ์ผ๊ด€์„ฑ ๋ฌธ์ œ'๋ผ๊ณ  ํ•ด. ๐Ÿ˜ฑ

์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž. ๋„ˆ์™€ ์นœ๊ตฌ๊ฐ€ ๊ฐ™์€ ๋…ธํŠธ์— ๋ฉ”๋ชจ๋ฅผ ํ•˜๋Š”๋ฐ, ๊ฐ์ž ๋…ธํŠธ์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ด. ๋„ˆ๋Š” "์˜ค๋Š˜ ๋ชจ์ž„ ์‹œ๊ฐ„: 6์‹œ"๋ผ๊ณ  ์ ์—ˆ๋Š”๋ฐ, ์นœ๊ตฌ๋Š” ์ž๊ธฐ ๋ณต์‚ฌ๋ณธ์— ๊ทธ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์•„์„œ ์—ฌ์ „ํžˆ "์˜ค๋Š˜ ๋ชจ์ž„ ์‹œ๊ฐ„: 5์‹œ"๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋Š” ๊ฑฐ์ง€. ์ด๋Ÿฐ ํ˜ผ๋ž€์ด ๋ฐ”๋กœ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์•ผ! ๐Ÿ“

๐Ÿ” ์‹ค์ƒํ™œ ์˜ˆ์‹œ: ๊ณต์œ  ๋ฌธ์„œ ํŽธ์ง‘

์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฌธ์„œ๋ฅผ ํŽธ์ง‘ํ•˜๋Š” ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ด. ๊ฐ์ž ์ž์‹ ์˜ ์ปดํ“จํ„ฐ์—์„œ ์ž‘์—…ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๋ชจ๋‘๊ฐ€ ๊ฐ™์€ ์ตœ์ข… ๋ฌธ์„œ๋ฅผ ๋ณด๊ณ  ์‹ถ์–ดํ•ด. ์ด๋•Œ ํ•„์š”ํ•œ ๊ฒƒ์ด '๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜'์ด์•ผ. C++์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์€ ์ด๋Ÿฐ ๋™๊ธฐํ™”๋ฅผ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜์ค€์—์„œ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์–ด!

2. C++11 ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์†Œ๊ฐœ: ๊ฒŒ์ž„์˜ ๊ทœ์น™์ด ๋ฐ”๋€Œ์—ˆ๋‹ค! ๐ŸŽฎ

C++11์ด ๋“ฑ์žฅํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์— ๊ด€ํ•œ ํ‘œ์ค€ํ™”๋œ ๊ทœ์น™์ด ์—†์—ˆ์–ด. ๊ฐ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ํ”Œ๋žซํผ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ–ˆ์ง€. ํ•˜์ง€๋งŒ C++11์—์„œ๋Š” ๊ณต์‹์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ๋„์ž…ํ•ด์„œ ๋ชจ๋“  C++ ํ”„๋กœ๊ทธ๋žจ์ด ๊ฐ™์€ ๊ทœ์น™์„ ๋”ฐ๋ฅด๊ฒŒ ๋์–ด. ์ด๊ฑด ์ •๋ง ํ˜๋ช…์ ์ธ ๋ณ€ํ™”์˜€์ง€! ๐Ÿš€

1998: C++98

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์— ๋Œ€ํ•œ ๊ณต์‹ ์ง€์› ์—†์Œ. ๊ฐœ๋ฐœ์ž๋“ค์€ ํ”Œ๋žซํผ๋ณ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(POSIX ์Šค๋ ˆ๋“œ, Win32 ์Šค๋ ˆ๋“œ ๋“ฑ)์— ์˜์กดํ–ˆ์–ด.

2011: C++11 ๐ŸŽ‰

ํ‘œ์ค€ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๋„์ž…! std::thread, std::atomic, ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ์ง€์ •์ž ๋“ฑ์ด ์ถ”๊ฐ€๋์–ด.

2014-2020: C++14, C++17, C++20

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๊ฐœ์„ ๊ณผ ํ™•์žฅ. ๋ณ‘๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜, std::atomic_ref, ํ–ฅ์ƒ๋œ ๋™๊ธฐํ™” ๊ธฐ๋Šฅ ๋“ฑ์ด ์ถ”๊ฐ€๋์–ด.

2023-2025: C++23๊ณผ ํ˜„์žฌ

๋” ์„ธ๋ จ๋œ ๋™์‹œ์„ฑ ๊ธฐ๋Šฅ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์ตœ์ ํ™”. ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ตœ์‹  ๊ธฐ๋Šฅ๋“ค!

C++11 ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์€ 'happens-before' ๊ด€๊ณ„์•ผ. ์ด๊ฑด "A ์—ฐ์‚ฐ์ด B ์—ฐ์‚ฐ๋ณด๋‹ค ๋จผ์ € ๋ฐœ์ƒํ•œ๋‹ค"๋Š” ๋ณด์žฅ์„ ์˜๋ฏธํ•ด. ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ์ด๋Ÿฐ ์ˆœ์„œ ๋ณด์žฅ์ด ๋งค์šฐ ์ค‘์š”ํ•˜์ง€! โฑ๏ธ

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๊ฐœ๋…์œผ๋กœ ๊ตฌ์„ฑ๋ผ ์žˆ์–ด:

1. ์›์ž์  ์—ฐ์‚ฐ (Atomic Operations) โš›๏ธ

๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ์ตœ์†Œ ๋‹จ์œ„์˜ ์—ฐ์‚ฐ. ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋ณผ ์ˆ˜ ์—†์–ด.

2. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ (Memory Ordering) ๐Ÿ”„

์—ฐ์‚ฐ๋“ค์ด ์–ด๋–ค ์ˆœ์„œ๋กœ ์‹คํ–‰๋˜๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ ๋ณด์ด๋Š”์ง€๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ทœ์น™.

3. ๋™๊ธฐํ™” (Synchronization) ๐Ÿ”’

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ ๊ฐ„์˜ ์ž‘์—…์„ ์กฐ์œจํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜.

์ด ๊ฐœ๋…๋“ค์ด ์™œ ์ค‘์š”ํ• ๊นŒ? ๋ฉ€ํ‹ฐ์ฝ”์–ด CPU์—์„œ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์™€ CPU๊ฐ€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ์ฝ”๋“œ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด. ์ด๊ฑธ '์žฌ๋ฐฐ์น˜(reordering)'๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜ต

๐Ÿงช ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ: ์žฌ๋ฐฐ์น˜์˜ ์œ„ํ—˜์„ฑ

// ์Šค๋ ˆ๋“œ 1
x = 1;  // ์—ฐ์‚ฐ A
y = 2;  // ์—ฐ์‚ฐ B

// ์Šค๋ ˆ๋“œ 2
if (y == 2) {  // ์—ฐ์‚ฐ C
    assert(x == 1);  // ์—ฐ์‚ฐ D - ์ด ๋‹จ์–ธ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์–ด!
}

์ง๊ด€์ ์œผ๋กœ๋Š” y๊ฐ€ 2๋ผ๋ฉด x๋Š” ๋ฐ˜๋“œ์‹œ 1์ด์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์ปดํŒŒ์ผ๋Ÿฌ๋‚˜ CPU๊ฐ€ ์—ฐ์‚ฐ A์™€ B์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์„œ ๋‹จ์–ธ๋ฌธ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์–ด! ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ๊ฑฐ์•ผ.

3. ์›์ž์  ์—ฐ์‚ฐ์˜ ๋งˆ๋ฒ•: ๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ์ตœ์†Œ ๋‹จ์œ„ โš›๏ธ

์›์ž์ (atomic)์ด๋ผ๋Š” ๋‹จ์–ด๋Š” ๊ทธ๋ฆฌ์Šค์–ด 'atomos'์—์„œ ์™”์–ด. '๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š”'์ด๋ผ๋Š” ๋œป์ด์ง€. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์›์ž์  ์—ฐ์‚ฐ์€ ์ค‘๊ฐ„์— ๋Š์–ด์งˆ ์ˆ˜ ์—†๊ณ , ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์—†๋Š” ์—ฐ์‚ฐ์„ ๋งํ•ด. ๐Ÿ”

์ผ๋ฐ˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ์›์ž์ ์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด, 64๋น„ํŠธ ์ •์ˆ˜๋ฅผ 32๋น„ํŠธ CPU์—์„œ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด, ์ด ์ž‘์—…์€ ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰˜์–ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ์ง€. ์ด๋•Œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋  ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜ฑ

์ผ๋ฐ˜ ์—ฐ์‚ฐ vs ์›์ž์  ์—ฐ์‚ฐ ์ผ๋ฐ˜ ์—ฐ์‚ฐ (count++) 1. ๋ฉ”๋ชจ๋ฆฌ์—์„œ count ๊ฐ’ ์ฝ๊ธฐ 2. count ๊ฐ’ ์ฆ๊ฐ€์‹œํ‚ค๊ธฐ 3. ์ฆ๊ฐ€๋œ ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค ์ˆ˜ ์žˆ์Œ! ์›์ž์  ์—ฐ์‚ฐ (atomic_count++) ํ•œ ๋ฒˆ์— ์™„๋ฃŒ๋˜๋Š” ๋ถˆ๊ฐ€๋ถ„์˜ ์—ฐ์‚ฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ์ ‘๊ทผ ๋ถˆ๊ฐ€!

C++์—์„œ๋Š” std::atomic ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ด ์›์ž์  ํƒ€์ž…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ด ํƒ€์ž…์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ํ•ญ์ƒ ์›์ž์ ์œผ๋กœ ์ˆ˜ํ–‰๋ผ. ๐Ÿ‘

๐Ÿงช ์›์ž์  ํƒ€์ž… ์‚ฌ์šฉ ์˜ˆ์ œ

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> counter(0);  // ์›์ž์  ์นด์šดํ„ฐ ์„ ์–ธ

void increment_counter() {
    for (int i = 0; i < 1000; ++i) {
        counter++;  // ์›์ž์  ์ฆ๊ฐ€ ์—ฐ์‚ฐ
    }
}

int main() {
    std::thread t1(increment_counter);
    std::thread t2(increment_counter);
    
    t1.join();
    t2.join();
    
    std::cout << "์ตœ์ข… ์นด์šดํ„ฐ ๊ฐ’: " << counter << std::endl;  // ํ•ญ์ƒ 2000์ด ์ถœ๋ ฅ๋ผ
    return 0;
}

์›์ž์  ์—ฐ์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด:

  1. ๋ถˆ๊ฐ€๋ถ„์„ฑ(Indivisibility): ์—ฐ์‚ฐ์ด ์ค‘๊ฐ„์— ์ค‘๋‹จ๋˜์ง€ ์•Š์•„.
  2. ๊ฐ€์‹œ์„ฑ(Visibility): ํ•œ ์Šค๋ ˆ๋“œ์˜ ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณด์—ฌ.
  3. ์ˆœ์„œ ๋ณด์žฅ(Ordering): ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๊ทœ์น™์— ๋”ฐ๋ผ ์—ฐ์‚ฐ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋ผ.

C++์—์„œ ์ง€์›ํ•˜๋Š” ์ฃผ์š” ์›์ž์  ์—ฐ์‚ฐ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„:

์—ฐ์‚ฐ ์„ค๋ช… ์˜ˆ์ œ
load ์›์ž์ ์œผ๋กœ ๊ฐ’์„ ์ฝ์Œ int value = atomic_var.load();
store ์›์ž์ ์œผ๋กœ ๊ฐ’์„ ์ €์žฅ atomic_var.store(10);
exchange ๊ฐ’์„ ๊ต์ฒดํ•˜๊ณ  ์ด์ „ ๊ฐ’์„ ๋ฐ˜ํ™˜ int old = atomic_var.exchange(new_value);
compare_exchange ์กฐ๊ฑด๋ถ€ ๊ต์ฒด (CAS ์—ฐ์‚ฐ) atomic_var.compare_exchange_strong(expected, desired);
fetch_add, fetch_sub ๊ฐ’์„ ๋”ํ•˜๊ฑฐ๋‚˜ ๋นผ๊ณ  ์ด์ „ ๊ฐ’ ๋ฐ˜ํ™˜ int prev = atomic_var.fetch_add(5);
fetch_and, fetch_or, fetch_xor ๋น„ํŠธ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ด์ „ ๊ฐ’ ๋ฐ˜ํ™˜ int prev = atomic_var.fetch_and(mask);

๐Ÿ’ก ์•Œ์•„๋‘๋ฉด ์ข‹์€ ํŒ

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

4. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ(Memory Ordering): ์ปดํ“จํ„ฐ์˜ ์ƒ๊ฐ ์ˆœ์„œ ์กฐ์ ˆํ•˜๊ธฐ ๐Ÿ”„

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

C++์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ์„ ์ œ๊ณตํ•ด:

C++ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ memory_order_seq_cst (์ˆœ์ฐจ์  ์ผ๊ด€์„ฑ) ๊ฐ€์žฅ ์—„๊ฒฉํ•˜๊ณ  ์ง๊ด€์ . ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์ผํ•œ ์ „์—ญ ์ˆœ์„œ๋ฅผ ๋ด„. (๊ธฐ๋ณธ๊ฐ’) memory_order_acq_rel (ํš๋“-ํ•ด์ œ) ํš๋“๊ณผ ํ•ด์ œ๋ฅผ ๋™์‹œ์— ์ˆ˜ํ–‰. ์–‘๋ฐฉํ–ฅ ๋™๊ธฐํ™”. memory_order_acquire (ํš๋“) ์ดํ›„ ์—ฐ์‚ฐ์ด ์ด์ „์œผ๋กœ ์ด๋™ ๋ชปํ•จ memory_order_release (ํ•ด์ œ) ์ด์ „ ์—ฐ์‚ฐ์ด ์ดํ›„๋กœ ์ด๋™ ๋ชปํ•จ memory_order_relaxed (์™„ํ™”๋จ) ์›์ž์„ฑ๋งŒ ๋ณด์žฅ. ์ˆœ์„œ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š์Œ. ๊ฐ€์žฅ ๋น ๋ฆ„. ์—„๊ฒฉํ•จ โ†‘ ์„ฑ๋Šฅ โ†“

๊ฐ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ์˜ ํŠน์ง•์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž:

1. memory_order_relaxed (์™„ํ™”๋จ) ๐Ÿƒโ€โ™‚๏ธ

๊ฐ€์žฅ ๋Š์Šจํ•œ ๋ชจ๋ธ. ์›์ž์„ฑ๋งŒ ๋ณด์žฅํ•˜๊ณ  ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์—ฐ์‚ฐ๊ณผ์˜ ์ˆœ์„œ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š์•„. ์„ฑ๋Šฅ์€ ๊ฐ€์žฅ ์ข‹์ง€๋งŒ, ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ€์žฅ ์–ด๋ ค์›Œ.

atomic_var.store(value, std::memory_order_relaxed);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋‹จ์ˆœ ์นด์šดํ„ฐ์ฒ˜๋Ÿผ ์ •ํ™•ํ•œ ๊ฐ’๋งŒ ์ค‘์š”ํ•˜๊ณ  ์ˆœ์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ.

2. memory_order_acquire (ํš๋“) ๐Ÿ”’

์ด ์—ฐ์‚ฐ ์ดํ›„์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ/์“ฐ๊ธฐ๊ฐ€ ์ด ์—ฐ์‚ฐ ์ด์ „์œผ๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ด. ์ฃผ๋กœ lock์„ ํš๋“ํ•  ๋•Œ ์‚ฌ์šฉ.

int value = atomic_var.load(std::memory_order_acquire);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋ฎคํ…์Šค ์ž ๊ธˆ ํš๋“, ๊ณต์œ  ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์ „ ๋™๊ธฐํ™”.

3. memory_order_release (ํ•ด์ œ) ๐Ÿ”“

์ด ์—ฐ์‚ฐ ์ด์ „์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ/์“ฐ๊ธฐ๊ฐ€ ์ด ์—ฐ์‚ฐ ์ดํ›„๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ด. ์ฃผ๋กœ lock์„ ํ•ด์ œํ•  ๋•Œ ์‚ฌ์šฉ.

atomic_var.store(value, std::memory_order_release);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋ฎคํ…์Šค ์ž ๊ธˆ ํ•ด์ œ, ๊ณต์œ  ๋ฐ์ดํ„ฐ ์ˆ˜์ • ํ›„ ๋™๊ธฐํ™”.

4. memory_order_acq_rel (ํš๋“-ํ•ด์ œ) ๐Ÿ”„

ํš๋“๊ณผ ํ•ด์ œ์˜ ํŠน์„ฑ์„ ๋ชจ๋‘ ๊ฐ€์ง. ์›์ž์  ์ฝ๊ธฐ-์ˆ˜์ •-์“ฐ๊ธฐ(RMW) ์—ฐ์‚ฐ์— ์‚ฌ์šฉ.

old_value = atomic_var.fetch_add(1, std::memory_order_acq_rel);

์‚ฌ์šฉ ์‚ฌ๋ก€: ์›์ž์  ์—…๋ฐ์ดํŠธ์™€ ๋™์‹œ์— ์–‘๋ฐฉํ–ฅ ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ.

5. memory_order_seq_cst (์ˆœ์ฐจ์  ์ผ๊ด€์„ฑ) โš–๏ธ

๊ฐ€์žฅ ์—„๊ฒฉํ•œ ๋ชจ๋ธ๋กœ, ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋ชจ๋“  ์›์ž์  ์—ฐ์‚ฐ์˜ ๋™์ผํ•œ ์ˆœ์„œ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด. C++์—์„œ ๊ธฐ๋ณธ๊ฐ’์ด์•ผ.

atomic_var.store(value);  // ๊ธฐ๋ณธ๊ฐ’์€ memory_order_seq_cst

์‚ฌ์šฉ ์‚ฌ๋ก€: ์ง๊ด€์ ์ธ ๋™์ž‘์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ.

๐Ÿ” ์‹ค์ œ ์˜ˆ์ œ: ์ƒ์‚ฐ์ž-์†Œ๋น„์ž ํŒจํ„ด

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<bool> data_ready(false);
int shared_data;

void producer() {
    shared_data = 42;  // ๋ฐ์ดํ„ฐ ์ค€๋น„
    // release ์ˆœ์„œ: ์ด์ „ ์“ฐ๊ธฐ๊ฐ€ ์ด ์›์ž์  ์“ฐ๊ธฐ ์ดํ›„๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š์Œ
    data_ready.store(true, std::memory_order_release);
}

void consumer() {
    // acquire ์ˆœ์„œ: ์ด ์›์ž์  ์ฝ๊ธฐ๊ฐ€ ์ดํ›„ ์ฝ๊ธฐ ์•ž์œผ๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š์Œ
    while (!data_ready.load(std::memory_order_acquire)) {
        // ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
    }
    
    // ์ด์ œ shared_data๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ์Œ
    std::cout << "๊ณต์œ  ๋ฐ์ดํ„ฐ: " << shared_data << std::endl;  // ํ•ญ์ƒ 42 ์ถœ๋ ฅ
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    
    t1.join();
    t2.join();
    
    return 0;
}

์ด ์˜ˆ์ œ์—์„œ memory_order_release์™€ memory_order_acquire์˜ ์กฐํ•ฉ์€ ์ƒ์‚ฐ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์„ค์ •ํ•œ ํ›„์—๋งŒ ์†Œ๋น„์ž๊ฐ€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด. ์ด๋Ÿฐ ํŒจํ„ด์„ "release-acquire ๋™๊ธฐํ™”"๋ผ๊ณ  ํ•ด.

๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์–ด. ํ™•์‹ ์ด ์—†๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์ธ memory_order_seq_cst๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•ด. ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ๋” ์™„ํ™”๋œ ๋ชจ๋ธ์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์–ด. ๐Ÿค”

5. ์‹ค์ „ ์˜ˆ์ œ: ์ฝ”๋“œ๋กœ ๋ณด๋Š” ์›์ž์  ์—ฐ์‚ฐ ๐Ÿ’ป

์ด์ œ ๋ช‡ ๊ฐ€์ง€ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž! ์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ ์‹ค์ „์œผ๋กœ ๋„˜์–ด๊ฐˆ ์‹œ๊ฐ„์ด์•ผ. ๐Ÿ‘จโ€๐Ÿ’ป

์˜ˆ์ œ 1: ๊ฐ„๋‹จํ•œ ์Šคํ•€๋ฝ(Spinlock) ๊ตฌํ˜„

์Šคํ•€๋ฝ์€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ ํ•˜๋‚˜์•ผ. ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด์ž!

#include <atomic>
#include <thread>
#include <iostream>

class SpinLock {
private:
    std::atomic<bool> lock_flag{false};

public:
    void lock() {
        // ์ด๋ฏธ false์ธ ๊ฐ’์„ true๋กœ ๊ต์ฒดํ•˜๋ ค๊ณ  ์‹œ๋„
        // ์„ฑ๊ณตํ•˜๋ฉด ์ž ๊ธˆ ํš๋“, ์‹คํŒจํ•˜๋ฉด ๊ณ„์† ์‹œ๋„
        bool expected = false;
        while (!lock_flag.compare_exchange_strong(expected, true,
                                                std::memory_order_acquire)) {
            expected = false;  // ์‹คํŒจ ์‹œ expected๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ์žฌ์„ค์ •
        }
    }

    void unlock() {
        lock_flag.store(false, std::memory_order_release);
    }
};

// ์‚ฌ์šฉ ์˜ˆ
SpinLock spin_lock;
int shared_counter = 0;

void increment_counter() {
    for (int i = 0; i < 1000; ++i) {
        spin_lock.lock();
        shared_counter++;  // ์ž„๊ณ„ ์˜์—ญ
        spin_lock.unlock();
    }
}

int main() {
    std::thread t1(increment_counter);
    std::thread t2(increment_counter);
    
    t1.join();
    t2.join();
    
    std::cout << "์ตœ์ข… ์นด์šดํ„ฐ ๊ฐ’: " << shared_counter << std::endl;  // ํ•ญ์ƒ 2000
    return 0;
}

์ด ์˜ˆ์ œ์—์„œ compare_exchange_strong ํ•จ์ˆ˜๋Š” ์›์ž์  ๋น„๊ต-๊ต์ฒด(Compare-And-Swap, CAS) ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•ด. ์ด ์—ฐ์‚ฐ์€ ๋งŽ์€ ๋ฝ-ํ”„๋ฆฌ(lock-free) ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ธฐ์ดˆ๊ฐ€ ๋ผ. ๐Ÿ”’

์˜ˆ์ œ 2: ์ด์ค‘ ๊ฒ€์‚ฌ ๋ฝํ‚น(Double-Checked Locking) ํŒจํ„ด

์‹ฑ๊ธ€ํ†ค(Singleton) ํŒจํ„ด์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ฒ•์ด์•ผ. ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•ด๋ณด์ž!

#include <atomic>
#include <mutex>
#include <memory>

class Singleton {
private:
    Singleton() { /* ์ดˆ๊ธฐํ™” ์ฝ”๋“œ */ }
    
    static std::atomic<Singleton*> instance;
    static std::mutex init_mutex;

public:
    static Singleton* getInstance() {
        Singleton* p = instance.load(std::memory_order_acquire);
        
        if (p == nullptr) {  // ์ฒซ ๋ฒˆ์งธ ๊ฒ€์‚ฌ
            std::lock_guard<std::mutex> lock(init_mutex);
            p = instance.load(std::memory_order_relaxed);
            
            if (p == nullptr) {  // ๋‘ ๋ฒˆ์งธ ๊ฒ€์‚ฌ
                p = new Singleton();
                instance.store(p, std::memory_order_release);
            }
        }
        
        return p;
    }
};

// ์ •์  ๋ฉค๋ฒ„ ์ดˆ๊ธฐํ™”
std::atomic<Singleton*> Singleton::instance{nullptr};
std::mutex Singleton::init_mutex;

์ด ํŒจํ„ด์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด๋ฏธ ์ƒ์„ฑ๋œ ๊ฒฝ์šฐ ๋ฎคํ…์Šค ์ž ๊ธˆ ์—†์ด ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์›์ž์  ์—ฐ์‚ฐ๊ณผ ์ ์ ˆํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•ด ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•ด. ๐Ÿ›ก๏ธ

์˜ˆ์ œ 3: ๋ฝ-ํ”„๋ฆฌ ํ(Lock-Free Queue)

๊ณ ์„ฑ๋Šฅ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋ฝ-ํ”„๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ์ค‘์š”ํ•ด. ๊ฐ„๋‹จํ•œ ๋ฝ-ํ”„๋ฆฌ ํ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž!

#include <atomic>
#include <memory>

template<typename T>
class LockFreeQueue {
private:
    struct Node {
        std::shared_ptr<T> data;
        std::atomic<Node*> next;
        
        Node() : next(nullptr) {}
    };
    
    std::atomic<Node*> head;
    std::atomic<Node*> tail;

public:
    LockFreeQueue() {
        Node* dummy = new Node();
        head.store(dummy);
        tail.store(dummy);
    }
    
    ~LockFreeQueue() {
        while (pop() != nullptr) {}
        delete head.load();
    }
    
    void push(T value) {
        std::shared_ptr<T> new_data = std::make_shared<T>(std::move(value));
        Node* new_node = new Node();
        new_node->data.swap(new_data);
        
        Node* old_tail = tail.load();
        while (!old_tail->next.compare_exchange_weak(
            nullptr, new_node, std::memory_order_acq_rel)) {
            old_tail = tail.load();
        }
        
        // ํ…Œ์ผ ํฌ์ธํ„ฐ ์—…๋ฐ์ดํŠธ
        tail.compare_exchange_strong(old_tail, new_node, std::memory_order_acq_rel);
    }
    
    std::shared_ptr<T> pop() {
        Node* old_head = head.load(std::memory_order_acquire);
        Node* next = old_head->next.load(std::memory_order_acquire);
        
        if (next == nullptr) {
            return nullptr;  // ํ๊ฐ€ ๋น„์–ด์žˆ์Œ
        }
        
        // ํ—ค๋“œ ํฌ์ธํ„ฐ ์—…๋ฐ์ดํŠธ
        if (head.compare_exchange_strong(old_head, next, std::memory_order_acq_rel)) {
            std::shared_ptr<T> result = next->data;
            delete old_head;  // ๋”๋ฏธ ๋…ธ๋“œ ์‚ญ์ œ
            return result;
        }
        
        return nullptr;  // ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋จผ์ € ํŒ ์ˆ˜ํ–‰
    }
};

์ด ๋ฝ-ํ”„๋ฆฌ ํ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ํ‘ธ์‹œ์™€ ํŒ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•ด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์ž‘๋™ํ•ด. ์›์ž์  ์—ฐ์‚ฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด ๋™๊ธฐํ™”๋ฅผ ๊ตฌํ˜„ํ–ˆ์–ด. ๐Ÿ”„

๐Ÿ’ก ์‹ค๋ฌด ํŒ

๋ฝ-ํ”„๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋งค์šฐ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ. ์žฌ๋Šฅ๋„ท์—์„œ ๊ณ ๊ธ‰ C++ ๊ฐœ๋ฐœ ์ง€์‹์„ ๊ณต์œ ํ•  ๋•Œ๋Š” ๊ฐ€๋Šฅํ•˜๋ฉด ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒ€์ฆ๋œ ์ปจํ…Œ์ด๋„ˆ์™€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ์กฐ์–ธํ•ด์ฃผ๋Š” ๊ฒŒ ์ข‹์•„. ์ง์ ‘ ๊ตฌํ˜„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•˜์ž!

6. ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด: ์ตœ์ ์˜ ๊ท ํ˜• ์ฐพ๊ธฐ โš–๏ธ

์›์ž์  ์—ฐ์‚ฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๊ณ ๋ คํ•ด์•ผ ํ•ด. ๋„ˆ๋ฌด ์—„๊ฒฉํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๊ณ , ๋„ˆ๋ฌด ์™„ํ™”๋œ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์€ ์ข‹์ง€๋งŒ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์œ„ํ—˜์ด ์ปค์ ธ. ๐Ÿคนโ€โ™€๏ธ

์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ์˜ ๊ท ํ˜• ์„ฑ๋Šฅ ์•ˆ์ „์„ฑ memory_order_relaxed ๋ฝ-ํ”„๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ memory_order_seq_cst ๋ฎคํ…์Šค์™€ ๋ฝ acquire-release ์ˆœ์„œ

์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด์—์„œ ๊ท ํ˜•์„ ์ฐพ๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ง€์นจ์„ ์‚ดํŽด๋ณด์ž:

1. ํ•„์š”ํ•œ ๊ณณ์—๋งŒ ์›์ž์  ์—ฐ์‚ฐ ์‚ฌ์šฉํ•˜๊ธฐ ๐ŸŽฏ

๋ชจ๋“  ๋ณ€์ˆ˜๋ฅผ std::atomic์œผ๋กœ ๋งŒ๋“ค๋ฉด ์•ˆ์ „ํ•˜๊ฒ ์ง€๋งŒ, ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ์ €ํ•˜๋  ์ˆ˜ ์žˆ์–ด. ์ •๋ง๋กœ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐ์ดํ„ฐ์—๋งŒ ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•˜์ž.

2. ์ ์ ˆํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ์„ ํƒํ•˜๊ธฐ ๐Ÿงฉ

๊ธฐ๋ณธ๊ฐ’์ธ memory_order_seq_cst๋Š” ๊ฐ€์žฅ ์•ˆ์ „ํ•˜์ง€๋งŒ ๊ฐ€์žฅ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค์–ด. ์ฝ”๋“œ์˜ ์˜๋„๋ฅผ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๋” ์™„ํ™”๋œ ์ˆœ์„œ๋ฅผ ์„ ํƒํ•ด ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด.

3. ๋ฐ์ดํ„ฐ ์ง€์—ญ์„ฑ ๊ณ ๋ คํ•˜๊ธฐ ๐Ÿ“

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ์บ์‹œ ๋ผ์ธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ž์ฃผ ์ˆ˜์ •ํ•˜๋ฉด "์บ์‹œ ๋ผ์ธ ํ•‘ํ" ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋ผ. ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๋‹ค๋ฅธ ์บ์‹œ ๋ผ์ธ์— ์œ„์น˜ํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์ž.

4. ๋ฝ๊ณผ ์›์ž์  ์—ฐ์‚ฐ ์ ์ ˆํžˆ ์กฐํ•ฉํ•˜๊ธฐ ๐Ÿ”„

๋ชจ๋“  ๋™๊ธฐํ™”๋ฅผ ์›์ž์  ์—ฐ์‚ฐ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋ง๊ณ , ๋ณต์žกํ•œ ์ž‘์—…์—๋Š” ๋ฎคํ…์Šค๋ฅผ, ๊ฐ„๋‹จํ•œ ํ”Œ๋ž˜๊ทธ๋‚˜ ์นด์šดํ„ฐ์—๋Š” ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•˜๋Š” ์‹์œผ๋กœ ์กฐํ•ฉํ•˜์ž.

5. ๋ฒค์น˜๋งˆํฌ์™€ ํ”„๋กœํŒŒ์ผ๋ง ํ™œ์šฉํ•˜๊ธฐ ๐Ÿ“Š

์ถ”์ธก๋ณด๋‹ค๋Š” ์ธก์ •์— ์˜์กดํ•˜์ž. ๋‹ค์–‘ํ•œ ๋™๊ธฐํ™” ๋ฐฉ์‹์„ ์‹ค์ œ๋กœ ๋ฒค์น˜๋งˆํฌํ•˜๊ณ  ํ”„๋กœํŒŒ์ผ๋งํ•ด์„œ ์ตœ์ ์˜ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋‚ด์ž.

๐Ÿ“ˆ ์„ฑ๋Šฅ ๋น„๊ต: ๋‹ค์–‘ํ•œ ๋™๊ธฐํ™” ๋ฐฉ์‹

๋™๊ธฐํ™” ๋ฐฉ์‹ ์ƒ๋Œ€์  ์„ฑ๋Šฅ ์•ˆ์ „์„ฑ ์‚ฌ์šฉ ๊ถŒ์žฅ ์ƒํ™ฉ
std::mutex ๐Ÿข ๋Š๋ฆผ ๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ ๋งค์šฐ ์•ˆ์ „ ๋ณต์žกํ•œ ์ž„๊ณ„ ์˜์—ญ, ๊ธด ์—ฐ์‚ฐ
std::atomic + seq_cst ๐Ÿ‡ ์ค‘๊ฐ„ ๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ ๋งค์šฐ ์•ˆ์ „ ๊ฐ„๋‹จํ•œ ์นด์šดํ„ฐ, ํ”Œ๋ž˜๊ทธ, ์ดˆ๊ธฐ ํ•™์Šต
std::atomic + acq_rel ๐Ÿ‡๐Ÿ‡ ๋น ๋ฆ„ ๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ ์•ˆ์ „ ์ƒ์‚ฐ์ž-์†Œ๋น„์ž ํŒจํ„ด, ๋™๊ธฐํ™” ์ง€์ 
std::atomic + relaxed ๐Ÿ‡๐Ÿ‡๐Ÿ‡ ๋งค์šฐ ๋น ๋ฆ„ ๐Ÿ›ก๏ธ ์ฃผ์˜ ํ•„์š” ๋…๋ฆฝ์  ์นด์šดํ„ฐ, ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ
๋ฝ-ํ”„๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๐Ÿ‡๐Ÿ‡๐Ÿ‡ ๋งค์šฐ ๋น ๋ฆ„ ๐Ÿ›ก๏ธ ๊ตฌํ˜„์ด ์–ด๋ ค์›€ ๊ณ ์„ฑ๋Šฅ ํ•„์ˆ˜, ๋Œ€๊ธฐ ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•œ ์‹œ์Šคํ…œ

๐ŸŒ ์‹ค์ œ ์‚ฌ๋ก€: ๊ฒŒ์ž„ ์—”์ง„์˜ ๋™์‹œ์„ฑ

ํ˜„๋Œ€ ๊ฒŒ์ž„ ์—”์ง„์€ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ์ž˜ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์•ผ. ๊ฒŒ์ž„ ์—”์ง„์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด:

  1. ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ: ์ฃผ๋กœ ๋ฝ-ํ”„๋ฆฌ ํ์™€ ์›์ž์  ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด ์ตœ๋Œ€ ์„ฑ๋Šฅ ํ™•๋ณด
  2. ๊ฒŒ์ž„ ๋กœ์ง: ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์ด ์ค‘์š”ํ•œ ๋ถ€๋ถ„์—๋Š” ๋ฎคํ…์Šค์™€ ๋ฝ ์‚ฌ์šฉ
  3. ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ: ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์™€ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ๊ฐ„ ๋™๊ธฐํ™”์— acquire-release ์ˆœ์„œ ํ™œ์šฉ

์žฌ๋Šฅ๋„ท์—์„œ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ ์ง€์‹์„ ๊ณต์œ ํ•  ๋•Œ, ์ด๋Ÿฐ ๊ท ํ˜• ์žกํžŒ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ฐ•์กฐํ•˜๋ฉด ๋” ์‹ค์šฉ์ ์ธ ์กฐ์–ธ์ด ๋  ๊ฑฐ์•ผ! ๐ŸŽฎ

7. ๋””๋ฒ„๊น… ํŒ: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ ๐Ÿ›

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ์ฝ”๋“œ์˜ ๋ฒ„๊ทธ๋Š” ์ฐพ๊ธฐ๊ฐ€ ๋งค์šฐ ์–ด๋ ค์›Œ. ๊ฒฝ์Ÿ ์กฐ๊ฑด(race condition)์ด๋‚˜ ๋ฐ๋“œ๋ฝ(deadlock)๊ฐ™์€ ๋ฌธ์ œ๋Š” ๊ฐ„ํ—์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๊ณ , ๋””๋ฒ„๊ฑฐ๋ฅผ ๋ถ™์ด๋ฉด ์‚ฌ๋ผ์ง€๋Š” ํ•˜์ด์  ๋ฒ„๊ทธ ๋ฒ„๊ทธ(Heisenbug)์˜ ํŠน์„ฑ์„ ๋ณด์ด๊ธฐ๋„ ํ•ด. ๐Ÿ˜ฑ

์›์ž์  ์—ฐ์‚ฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๊ด€๋ จ ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•œ ํŒ์„ ์•Œ์•„๋ณด์ž:

1. ์Šค๋ ˆ๋“œ ์ƒ˜ํ‹ฐํƒ€์ด์ €(Thread Sanitizer) ์‚ฌ์šฉํ•˜๊ธฐ ๐Ÿงน

GCC์™€ Clang ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ์Šค๋ ˆ๋“œ ์ƒ˜ํ‹ฐํƒ€์ด์ €๋Š” ๋ฐ์ดํ„ฐ ๊ฒฝ์Ÿ์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•ด์ค˜. ์ปดํŒŒ์ผ ์‹œ -fsanitize=thread ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ผ.

g++ -fsanitize=thread -g -O1 -std=c++17 your_program.cpp

ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๊ฒฝ์Ÿ์ด ๋ฐœ์ƒํ•œ ์œ„์น˜์™€ ๊ด€๋ จ ์Šค๋ ˆ๋“œ ์ •๋ณด๋ฅผ ์ƒ์„ธํžˆ ๋ณด์—ฌ์ค˜.

2. ์ •์  ๋ถ„์„ ๋„๊ตฌ ํ™œ์šฉํ•˜๊ธฐ ๐Ÿ”

Clang Static Analyzer, PVS-Studio, Coverity ๊ฐ™์€ ์ •์  ๋ถ„์„ ๋„๊ตฌ๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ ๋„ ์ž ์žฌ์ ์ธ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ์–ด.

3. ๋กœ๊น…๊ณผ ํŠธ๋ ˆ์ด์‹ฑ ๊ฐ•ํ™”ํ•˜๊ธฐ ๐Ÿ“

๊ฐ ์Šค๋ ˆ๋“œ์˜ ์ž‘์—…์„ ์ƒ์„ธํžˆ ๋กœ๊น…ํ•˜๊ณ , ์›์ž์  ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๊ธฐ๋กํ•ด๋‘๋ฉด ๋ฌธ์ œ ํ•ด๊ฒฐ์— ๋„์›€์ด ๋ผ. ๋‹จ, ๋กœ๊น… ์ž์ฒด๊ฐ€ ํƒ€์ด๋ฐ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ฃผ์˜ํ•ด์•ผ ํ•ด.

std::atomic<int> counter(0);
int result = counter.fetch_add(1, std::memory_order_acq_rel);
std::cout << "Thread " << std::this_thread::get_id() 
          << " incremented counter from " << result 
          << " to " << (result + 1) << std::endl;

4. ๋‹จ์ˆœํ™” ์ „๋žต ์‚ฌ์šฉํ•˜๊ธฐ ๐Ÿงฉ

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ๋‹จ์ˆœํ™”ํ•ด์„œ ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์˜ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž. ๋ถˆํ•„์š”ํ•œ ๋ณต์žก์„ฑ์„ ์ œ๊ฑฐํ•˜๋ฉด ๋ฌธ์ œ์˜ ๋ณธ์งˆ์„ ํŒŒ์•…ํ•˜๊ธฐ ์‰ฌ์›Œ์ ธ.

5. ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ ์‹คํ–‰ํ•˜๊ธฐ ๐Ÿ‹๏ธโ€โ™‚๏ธ

๋‹ค์–‘ํ•œ CPU ์ฝ”์–ด ์ˆ˜, ๋ถ€ํ•˜ ์กฐ๊ฑด, ํƒ€์ด๋ฐ์—์„œ ํ”„๋กœ๊ทธ๋žจ์„ ๋ฐ˜๋ณต ์‹คํ–‰ํ•ด๋ณด์ž. ๊ฐ„ํ—์ ์ธ ๋ฌธ์ œ๋Š” ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ์—์„œ ๋” ์ž์ฃผ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด.

// ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ ์˜ˆ์ œ
for (int i = 0; i < 10000; ++i) {
    run_concurrent_test();
    if (i % 100 == 0) {
        std::cout << "Completed " << i << " iterations..." << std::endl;
    }
}

๐Ÿšจ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ์ฑ…

๋ฌธ์ œ ์ฆ์ƒ ๊ฐ€๋Šฅํ•œ ์›์ธ ํ•ด๊ฒฐ์ฑ…
๋ฐ์ดํ„ฐ ๊ฒฝ์Ÿ ๊ฐ„ํ—์ ์ธ ํฌ๋ž˜์‹œ, ์†์ƒ๋œ ๋ฐ์ดํ„ฐ ๋น„์›์ž์  ๋ณ€์ˆ˜์— ๋™์‹œ ์ ‘๊ทผ std::atomic ์‚ฌ์šฉ ๋˜๋Š” ๋ฎคํ…์Šค๋กœ ๋ณดํ˜ธ
๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ฌธ์ œ ํŠน์ • ํ”Œ๋žซํผ์—์„œ๋งŒ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๊ทธ ๋„ˆ๋ฌด ์™„ํ™”๋œ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ์‚ฌ์šฉ ๋” ๊ฐ•๋ ฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ
ABA ๋ฌธ์ œ ๋ฝ-ํ”„๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋…ผ๋ฆฌ์  ์˜ค๋ฅ˜ ๊ฐ’์ด Aโ†’Bโ†’A๋กœ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์‹คํŒจ ๋ฒ„์ „ ์นด์šดํ„ฐ ์ถ”๊ฐ€ ๋˜๋Š” std::atomic_shared_ptr ์‚ฌ์šฉ
๋ฐ๋“œ๋ฝ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฉˆ์ถค ์ž˜๋ชป๋œ ๋ฝ ํš๋“ ์ˆœ์„œ ์ผ๊ด€๋œ ๋ฝ ํš๋“ ์ˆœ์„œ ์œ ์ง€ ๋˜๋Š” std::lock ์‚ฌ์šฉ
์บ์‹œ ๋ผ์ธ ๊ฒฝํ•ฉ ์˜ˆ์ƒ๋ณด๋‹ค ๋‚ฎ์€ ์„ฑ๋Šฅ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ์บ์‹œ ๋ผ์ธ ์ˆ˜์ • ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์žฌ์„ค๊ณ„ ๋˜๋Š” ํŒจ๋”ฉ ์ถ”๊ฐ€

๐Ÿ” ๋””๋ฒ„๊น… ์‚ฌ๋ก€ ์—ฐ๊ตฌ: ๊ฐ„ํ—์  ํฌ๋ž˜์‹œ

์žฌ๋Šฅ๋„ท์˜ ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ณต์œ ํ•œ ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ์‚ดํŽด๋ณด์ž. ๊ณ ์„ฑ๋Šฅ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ„ํ—์ ์ธ ํฌ๋ž˜์‹œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด:

// ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ
struct SharedData {
    int value;
    std::atomic<bool> is_ready{false};
};

SharedData* data = nullptr;

void producer_thread() {
    data = new SharedData();  // 1. ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
    data->value = 42;         // 2. ๊ฐ’ ์„ค์ •
    data->is_ready.store(true, std::memory_order_relaxed);  // 3. ํ”Œ๋ž˜๊ทธ ์„ค์ •
}

void consumer_thread() {
    if (data->is_ready.load(std::memory_order_relaxed)) {  // ํ”Œ๋ž˜๊ทธ ํ™•์ธ
        use_value(data->value);  // ๊ฐ€๋” ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ๊ฐ’ ๋˜๋Š” nullptr ์ฐธ์กฐ
    }
}

๋ฌธ์ œ ์›์ธ: consumer_thread๊ฐ€ data๊ฐ€ nullptr์ธ์ง€ ํ™•์ธํ•˜์ง€ ์•Š๊ณ , relaxed ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ data ํฌ์ธํ„ฐ ์„ค์ •๊ณผ is_ready ํ”Œ๋ž˜๊ทธ ์„ค์ • ์‚ฌ์ด์— ์ˆœ์„œ ๋ณด์žฅ์ด ์—†์—ˆ์–ด.

ํ•ด๊ฒฐ์ฑ…:

// ์ˆ˜์ •๋œ ์ฝ”๋“œ
std::atomic<SharedData*> data{nullptr};  // ํฌ์ธํ„ฐ๋ฅผ ์›์ž์ ์œผ๋กœ ๋งŒ๋“ฆ

void producer_thread() {
    SharedData* new_data = new SharedData();
    new_data->value = 42;
    new_data->is_ready.store(true, std::memory_order_release);
    data.store(new_data, std::memory_order_release);  // ์›์ž์  ํฌ์ธํ„ฐ ์—…๋ฐ์ดํŠธ
}

void consumer_thread() {
    SharedData* current = data.load(std::memory_order_acquire);  // ์›์ž์  ๋กœ๋“œ
    if (current && current->is_ready.load(std::memory_order_acquire)) {
        use_value(current->value);  // ์ด์ œ ์•ˆ์ „ํ•จ
    }
}

์ด ์ˆ˜์ •์œผ๋กœ ํฌ์ธํ„ฐ ์ ‘๊ทผ์ด ์•ˆ์ „ํ•ด์ง€๊ณ , acquire-release ์ˆœ์„œ๋กœ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์‹œ์„ฑ์ด ๋ณด์žฅ๋ผ!

8. ๋ฏธ๋ž˜ ์ „๋ง: C++23๊ณผ ๊ทธ ์ดํ›„ ๐Ÿ”ฎ

C++ ์–ธ์–ด๋Š” ๊ณ„์† ๋ฐœ์ „ํ•˜๊ณ  ์žˆ๊ณ , ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์•ผ. 2025๋…„ ํ˜„์žฌ ์‹œ์ ์—์„œ ์ตœ์‹  ํ‘œ์ค€์ธ C++23๊ณผ ์•ž์œผ๋กœ์˜ ๋ฐœ์ „ ๋ฐฉํ–ฅ์„ ์‚ดํŽด๋ณด์ž! ๐Ÿš€

C++23์˜ ์ฃผ์š” ๊ฐœ์„ ์‚ฌํ•ญ

  1. std::atomic_ref: ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ์›์ž์ ์œผ๋กœ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์ž„์‹œ๋กœ ์›์ž์„ฑ์ด ํ•„์š”ํ•  ๋•Œ ์œ ์šฉํ•ด.
  2. ํ–ฅ์ƒ๋œ hazard pointer: ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ๋” ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋์–ด.
  3. ํ™•์žฅ๋œ ์›์ž์  ๋Œ€๊ธฐ ์—ฐ์‚ฐ: ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋Œ€๊ธฐ ํ•จ์ˆ˜๋“ค์ด ์ถ”๊ฐ€๋์–ด.
  4. ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๋ช…ํ™•ํ™”: ๊ธฐ์กด ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๋ชจํ˜ธํ•œ ๋ถ€๋ถ„๋“ค์ด ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋์–ด.

๋ฏธ๋ž˜ ๋ฐœ์ „ ๋ฐฉํ–ฅ

  1. ํ•˜๋“œ์›จ์–ด ํŠธ๋žœ์žญ์…˜ ๋ฉ”๋ชจ๋ฆฌ(HTM) ์ง€์›: ์ผ๋ถ€ ์ตœ์‹  CPU์—์„œ ์ง€์›ํ•˜๋Š” HTM์„ C++ ํ‘œ์ค€์— ํ†ตํ•ฉํ•˜๋ ค๋Š” ๋…ธ๋ ฅ์ด ์ง„ํ–‰ ์ค‘์ด์•ผ.
  2. ๋” ๋†’์€ ์ˆ˜์ค€์˜ ๋™์‹œ์„ฑ ์ถ”์ƒํ™”: ์›์ž์  ์—ฐ์‚ฐ์„ ์ง์ ‘ ๋‹ค๋ฃจ๋Š” ๋Œ€์‹  ๋” ์•ˆ์ „ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ๊ณ ์ˆ˜์ค€ ์ถ”์ƒํ™”๊ฐ€ ๊ฐœ๋ฐœ๋˜๊ณ  ์žˆ์–ด.
  3. ์ฝ”๋ฃจํ‹ด๊ณผ์˜ ํ†ตํ•ฉ: ์ฝ”๋ฃจํ‹ด๊ณผ ์›์ž์  ์—ฐ์‚ฐ์˜ ์กฐํ•ฉ์œผ๋กœ ๋” ํšจ์œจ์ ์ธ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์ด ๋งŒ๋“ค์–ด์ง€๊ณ  ์žˆ์–ด.
  4. ๋ณ‘๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ™•์žฅ: ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ณ‘๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋” ๋งŽ์€ ๊ธฐ๋Šฅ๊ณผ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•˜๋„๋ก ํ™•์žฅ๋˜๊ณ  ์žˆ์–ด.

๐Ÿงช C++23 atomic_ref ์˜ˆ์ œ

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>

void increment_vector(std::vector<int>& vec, size_t index) {
    // ๋ฒกํ„ฐ ์š”์†Œ์— ๋Œ€ํ•œ ์›์ž์  ์ฐธ์กฐ ์ƒ์„ฑ
    std::atomic_ref<int> atomic_element(vec[index]);
    
    for (int i = 0; i < 1000; ++i) {
        atomic_element.fetch_add(1, std::memory_order_relaxed);
    }
}

int main() {
    std::vector<int> numbers(10, 0);
    
    std::vector<std::thread> threads;
    for (size_t i = 0; i < 5; ++i) {
        // ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ๋ฒกํ„ฐ ์š”์†Œ์— ์ ‘๊ทผ
        threads.emplace_back(increment_vector, std::ref(numbers), i % numbers.size());
    }
    
    for (auto& t : threads) {
        t.join();
    }
    
    // ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    for (size_t i = 0; i < numbers.size(); ++i) {
        std::cout << "numbers[" << i << "] = " << numbers[i] << std::endl;
    }
    
    return 0;
}

์ด ์˜ˆ์ œ์—์„œ std::atomic_ref๋Š” ๊ธฐ์กด ๋ฒกํ„ฐ ์š”์†Œ๋ฅผ ์›์ž์ ์œผ๋กœ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์ด์ „์—๋Š” ์ด๋Ÿฐ ์ž‘์—…์„ ์œ„ํ•ด ๋ณ„๋„์˜ ์›์ž์  ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋ฎคํ…์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์–ด.

๐Ÿ“š ๋” ๋ฐฐ์šฐ๊ธฐ ์œ„ํ•œ ์ž๋ฃŒ

  1. ๋„์„œ: "C++ Concurrency in Action" (Anthony Williams) - ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์— ๋Œ€ํ•œ ๊ฐ€์žฅ ์ข‹์€ ์ฐธ๊ณ ์„œ
  2. ์›น์‚ฌ์ดํŠธ: cppreference.com - ์ตœ์‹  C++ ํ‘œ์ค€์˜ ์›์ž์  ์—ฐ์‚ฐ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๋ฌธ์„œ
  3. ๋ธ”๋กœ๊ทธ: Herb Sutter์˜ "Sutter's Mill" - C++ ๋™์‹œ์„ฑ์— ๊ด€ํ•œ ์‹ฌ์ธต์ ์ธ ๊ธ€๋“ค
  4. ์ปจํผ๋Ÿฐ์Šค: CppCon, C++Now - ์ตœ์‹  C++ ๋™์‹œ์„ฑ ๊ธฐ์ˆ ์— ๊ด€ํ•œ ๋ฐœํ‘œ ์˜์ƒ
  5. ์ปค๋ฎค๋‹ˆํ‹ฐ: ์žฌ๋Šฅ๋„ท์˜ C++ ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ - ์‹ค๋ฌด ๊ฒฝํ—˜๊ณผ ์ง€์‹์„ ๊ณต์œ ํ•˜๋Š” ์ข‹์€ ์žฅ์†Œ!

๋งˆ๋ฌด๋ฆฌ: ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์˜ ์—ฌ์ • ๐Ÿ

์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” C++์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์ด๋ผ๋Š” ๋ณต์žกํ•˜์ง€๋งŒ ๋งค๋ ฅ์ ์ธ ์„ธ๊ณ„๋ฅผ ํ•จ๊ป˜ ํƒํ—˜ํ–ˆ์–ด. ์ด ์ง€์‹์€ ํ˜„๋Œ€ ๋ฉ€ํ‹ฐ์ฝ”์–ด ์‹œ์Šคํ…œ์—์„œ ํšจ์œจ์ ์ด๊ณ  ์•ˆ์ „ํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ด์ง€! ๐Ÿงญ

ํ•ต์‹ฌ ๋‚ด์šฉ์„ ๋‹ค์‹œ ์ •๋ฆฌํ•ด๋ณด์ž:

  1. ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์€ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ณต์œ ํ•˜๊ณ  ์ ‘๊ทผํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ทœ์น™์„ ์ •์˜ํ•ด.
  2. ์›์ž์  ์—ฐ์‚ฐ์€ ์ค‘๊ฐ„์— ๋Š์–ด์งˆ ์ˆ˜ ์—†๋Š” ๋ถˆ๊ฐ€๋ถ„์˜ ์—ฐ์‚ฐ์œผ๋กœ, ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ๋ณด์žฅํ•ด.
  3. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋Š” ์—ฐ์‚ฐ๋“ค์ด ์–ด๋–ค ์ˆœ์„œ๋กœ ์‹คํ–‰๋˜๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ ๋ณด์ด๋Š”์ง€๋ฅผ ์ œ์–ดํ•ด.
  4. ์„ฑ๋Šฅ๊ณผ ์•ˆ์ „์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ์ฐพ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด. ์ƒํ™ฉ์— ๋งž๋Š” ์ ์ ˆํ•œ ๋™๊ธฐํ™” ๋ฐฉ์‹์„ ์„ ํƒํ•˜์ž.
  5. ๋””๋ฒ„๊น… ๋„๊ตฌ์™€ ๊ธฐ๋ฒ•์„ ํ™œ์šฉํ•ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฌธ์ œ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด.

C++์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์€ ์ฒ˜์Œ์—๋Š” ์–ด๋ ต๊ฒŒ ๋Š๊ปด์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ดํ•ดํ•˜๊ณ  ๋‚˜๋ฉด ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋ผ. ์ด ์ง€์‹์„ ๋ฐ”ํƒ•์œผ๋กœ ๋” ์•ˆ์ •์ ์ด๊ณ  ํšจ์œจ์ ์ธ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ! ๐Ÿ’ช

์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์‹์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ์ฐพ์„ ๋•Œ, ์ด๋Ÿฐ ์‹ฌ์ธต์ ์ธ ์ฃผ์ œ์— ๋Œ€ํ•œ ์ดํ•ด๋Š” ํฐ ๊ฐ€์น˜๊ฐ€ ์žˆ์–ด. ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ•จ๊ป˜ ๋ฐฐ์šฐ๊ณ  ์„ฑ์žฅํ•˜๋Š” ์—ฌ์ •์„ ๊ณ„์†ํ•ด๋‚˜๊ฐ€์ž! ๐ŸŒฑ

"๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์–ด๋ ต์ง€๋งŒ, ์˜ฌ๋ฐ”๋ฅธ ๋„๊ตฌ์™€ ์ง€์‹์œผ๋กœ ๋ฌด์žฅํ•˜๋ฉด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ์—†๋‹ค."

- ํ˜„๋Œ€ C++ ๊ฐœ๋ฐœ์ž์˜ ๋ช…์–ธ

1. ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๊ธฐ์ดˆ: ์ปดํ“จํ„ฐ๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ๋ฐฉ๋ฒ• ๐Ÿง 

์ปดํ“จํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ๋Œ€ํ•œ ์ฐฝ๊ณ ๋ผ๊ณ  ์ƒ์ƒํ•ด๋ด. ์ด ์ฐฝ๊ณ ์—๋Š” ์ˆ˜๋งŽ์€ ์„ ๋ฐ˜(๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ)์ด ์žˆ๊ณ , ๊ฐ ์„ ๋ฐ˜์—๋Š” ๋ฌผ๊ฑด(๋ฐ์ดํ„ฐ)์ด ๋†“์—ฌ ์žˆ์–ด. ๋‹จ์ผ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ์ฐฝ๊ณ  ๊ด€๋ฆฌ์ž๊ฐ€ ํ•œ ๋ช…๋ฟ์ด๋ผ ๋ชจ๋“  ๊ฒŒ ์งˆ์„œ์ •์—ฐํ•˜๊ฒŒ ์ง„ํ–‰๋ผ. ํ•˜์ง€๋งŒ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์€ ์—ฌ๋Ÿฌ ๊ด€๋ฆฌ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ฐฝ๊ณ ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„. ์ด๋Ÿด ๋•Œ ํ˜ผ๋ž€์ด ์ƒ๊ธฐ์ง€ ์•Š์œผ๋ ค๋ฉด ํŠน๋ณ„ํ•œ ๊ทœ์น™์ด ํ•„์š”ํ•˜์ง€! ๐Ÿข

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์ด๋ž€? ๐Ÿค”

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์€ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฉ”๋ชจ๋ฆฌ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ •์˜ํ•˜๋Š” ๊ทœ์น™์˜ ์ง‘ํ•ฉ์ด์•ผ. ์ด ๊ทœ์น™๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ์— ๋‹ตํ•ด์ค˜:

  1. ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•  ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ?
  2. ํ•œ ์Šค๋ ˆ๋“œ์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ ์–ธ์ œ ๋ณด์ด๊ฒŒ ๋ ๊นŒ?
  3. ์ปดํŒŒ์ผ๋Ÿฌ์™€ CPU๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•  ๋•Œ ์–ด๋–ค ๊ฐ€์ •์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

C++์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ์ดํ•ดํ•˜๊ธฐ ์ „์—, ๋จผ์ € ์ปดํ“จํ„ฐ ํ•˜๋“œ์›จ์–ด๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž. ํ˜„๋Œ€ ์ปดํ“จํ„ฐ๋Š” CPU, ์บ์‹œ, ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ๋ผ๋Š” ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์–ด. ๐Ÿ–ฅ๏ธ

CPU ์ฝ”์–ด 1 CPU ์ฝ”์–ด 2 L1/L2 ์บ์‹œ L1/L2 ์บ์‹œ ๊ณต์œ  L3 ์บ์‹œ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ ํ˜„๋Œ€ ์ปดํ“จํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ

์ด ๊ตฌ์กฐ์—์„œ ์ค‘์š”ํ•œ ์ ์€ ๊ฐ CPU ์ฝ”์–ด๊ฐ€ ์ž์‹ ๋งŒ์˜ ์บ์‹œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฑฐ์•ผ. ๊ทธ๋ž˜์„œ ํ•œ ์ฝ”์–ด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด๋„ ๋‹ค๋ฅธ ์ฝ”์–ด๋Š” ์ž๊ธฐ ์บ์‹œ์— ์žˆ๋Š” ์˜ค๋ž˜๋œ ๊ฐ’์„ ๊ณ„์† ๋ณด๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์–ด. ์ด๋Ÿฐ ํ˜„์ƒ์„ '์บ์‹œ ์ผ๊ด€์„ฑ ๋ฌธ์ œ'๋ผ๊ณ  ํ•ด. ๐Ÿ˜ฑ

์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž. ๋„ˆ์™€ ์นœ๊ตฌ๊ฐ€ ๊ฐ™์€ ๋…ธํŠธ์— ๋ฉ”๋ชจ๋ฅผ ํ•˜๋Š”๋ฐ, ๊ฐ์ž ๋…ธํŠธ์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ด. ๋„ˆ๋Š” "์˜ค๋Š˜ ๋ชจ์ž„ ์‹œ๊ฐ„: 6์‹œ"๋ผ๊ณ  ์ ์—ˆ๋Š”๋ฐ, ์นœ๊ตฌ๋Š” ์ž๊ธฐ ๋ณต์‚ฌ๋ณธ์— ๊ทธ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์•„์„œ ์—ฌ์ „ํžˆ "์˜ค๋Š˜ ๋ชจ์ž„ ์‹œ๊ฐ„: 5์‹œ"๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋Š” ๊ฑฐ์ง€. ์ด๋Ÿฐ ํ˜ผ๋ž€์ด ๋ฐ”๋กœ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์•ผ! ๐Ÿ“

๐Ÿ” ์‹ค์ƒํ™œ ์˜ˆ์‹œ: ๊ณต์œ  ๋ฌธ์„œ ํŽธ์ง‘

์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฌธ์„œ๋ฅผ ํŽธ์ง‘ํ•˜๋Š” ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ด. ๊ฐ์ž ์ž์‹ ์˜ ์ปดํ“จํ„ฐ์—์„œ ์ž‘์—…ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๋ชจ๋‘๊ฐ€ ๊ฐ™์€ ์ตœ์ข… ๋ฌธ์„œ๋ฅผ ๋ณด๊ณ  ์‹ถ์–ดํ•ด. ์ด๋•Œ ํ•„์š”ํ•œ ๊ฒƒ์ด '๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜'์ด์•ผ. C++์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์€ ์ด๋Ÿฐ ๋™๊ธฐํ™”๋ฅผ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜์ค€์—์„œ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์–ด!

2. C++11 ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์†Œ๊ฐœ: ๊ฒŒ์ž„์˜ ๊ทœ์น™์ด ๋ฐ”๋€Œ์—ˆ๋‹ค! ๐ŸŽฎ

C++11์ด ๋“ฑ์žฅํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์— ๊ด€ํ•œ ํ‘œ์ค€ํ™”๋œ ๊ทœ์น™์ด ์—†์—ˆ์–ด. ๊ฐ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ํ”Œ๋žซํผ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ–ˆ์ง€. ํ•˜์ง€๋งŒ C++11์—์„œ๋Š” ๊ณต์‹์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ๋„์ž…ํ•ด์„œ ๋ชจ๋“  C++ ํ”„๋กœ๊ทธ๋žจ์ด ๊ฐ™์€ ๊ทœ์น™์„ ๋”ฐ๋ฅด๊ฒŒ ๋์–ด. ์ด๊ฑด ์ •๋ง ํ˜๋ช…์ ์ธ ๋ณ€ํ™”์˜€์ง€! ๐Ÿš€

1998: C++98

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์— ๋Œ€ํ•œ ๊ณต์‹ ์ง€์› ์—†์Œ. ๊ฐœ๋ฐœ์ž๋“ค์€ ํ”Œ๋žซํผ๋ณ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(POSIX ์Šค๋ ˆ๋“œ, Win32 ์Šค๋ ˆ๋“œ ๋“ฑ)์— ์˜์กดํ–ˆ์–ด.

2011: C++11 ๐ŸŽ‰

ํ‘œ์ค€ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๋„์ž…! std::thread, std::atomic, ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ์ง€์ •์ž ๋“ฑ์ด ์ถ”๊ฐ€๋์–ด.

2014-2020: C++14, C++17, C++20

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ๊ฐœ์„ ๊ณผ ํ™•์žฅ. ๋ณ‘๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜, std::atomic_ref, ํ–ฅ์ƒ๋œ ๋™๊ธฐํ™” ๊ธฐ๋Šฅ ๋“ฑ์ด ์ถ”๊ฐ€๋์–ด.

2023-2025: C++23๊ณผ ํ˜„์žฌ

๋” ์„ธ๋ จ๋œ ๋™์‹œ์„ฑ ๊ธฐ๋Šฅ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์ตœ์ ํ™”. ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ตœ์‹  ๊ธฐ๋Šฅ๋“ค!

C++11 ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์€ 'happens-before' ๊ด€๊ณ„์•ผ. ์ด๊ฑด "A ์—ฐ์‚ฐ์ด B ์—ฐ์‚ฐ๋ณด๋‹ค ๋จผ์ € ๋ฐœ์ƒํ•œ๋‹ค"๋Š” ๋ณด์žฅ์„ ์˜๋ฏธํ•ด. ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ์ด๋Ÿฐ ์ˆœ์„œ ๋ณด์žฅ์ด ๋งค์šฐ ์ค‘์š”ํ•˜์ง€! โฑ๏ธ

๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๊ฐœ๋…์œผ๋กœ ๊ตฌ์„ฑ๋ผ ์žˆ์–ด:

1. ์›์ž์  ์—ฐ์‚ฐ (Atomic Operations) โš›๏ธ

๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ์ตœ์†Œ ๋‹จ์œ„์˜ ์—ฐ์‚ฐ. ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋ณผ ์ˆ˜ ์—†์–ด.

2. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ (Memory Ordering) ๐Ÿ”„

์—ฐ์‚ฐ๋“ค์ด ์–ด๋–ค ์ˆœ์„œ๋กœ ์‹คํ–‰๋˜๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ ๋ณด์ด๋Š”์ง€๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ทœ์น™.

3. ๋™๊ธฐํ™” (Synchronization) ๐Ÿ”’

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ ๊ฐ„์˜ ์ž‘์—…์„ ์กฐ์œจํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜.

์ด ๊ฐœ๋…๋“ค์ด ์™œ ์ค‘์š”ํ• ๊นŒ? ๋ฉ€ํ‹ฐ์ฝ”์–ด CPU์—์„œ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์™€ CPU๊ฐ€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ์ฝ”๋“œ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด. ์ด๊ฑธ '์žฌ๋ฐฐ์น˜(reordering)'๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜ต

๐Ÿงช ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ: ์žฌ๋ฐฐ์น˜์˜ ์œ„ํ—˜์„ฑ

// ์Šค๋ ˆ๋“œ 1
x = 1;  // ์—ฐ์‚ฐ A
y = 2;  // ์—ฐ์‚ฐ B

// ์Šค๋ ˆ๋“œ 2
if (y == 2) {  // ์—ฐ์‚ฐ C
    assert(x == 1);  // ์—ฐ์‚ฐ D - ์ด ๋‹จ์–ธ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์–ด!
}

์ง๊ด€์ ์œผ๋กœ๋Š” y๊ฐ€ 2๋ผ๋ฉด x๋Š” ๋ฐ˜๋“œ์‹œ 1์ด์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์ปดํŒŒ์ผ๋Ÿฌ๋‚˜ CPU๊ฐ€ ์—ฐ์‚ฐ A์™€ B์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์„œ ๋‹จ์–ธ๋ฌธ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์–ด! ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๊ณผ ์›์ž์  ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ๊ฑฐ์•ผ.

3. ์›์ž์  ์—ฐ์‚ฐ์˜ ๋งˆ๋ฒ•: ๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ์ตœ์†Œ ๋‹จ์œ„ โš›๏ธ

์›์ž์ (atomic)์ด๋ผ๋Š” ๋‹จ์–ด๋Š” ๊ทธ๋ฆฌ์Šค์–ด 'atomos'์—์„œ ์™”์–ด. '๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š”'์ด๋ผ๋Š” ๋œป์ด์ง€. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์›์ž์  ์—ฐ์‚ฐ์€ ์ค‘๊ฐ„์— ๋Š์–ด์งˆ ์ˆ˜ ์—†๊ณ , ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์—†๋Š” ์—ฐ์‚ฐ์„ ๋งํ•ด. ๐Ÿ”

์ผ๋ฐ˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ์›์ž์ ์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด, 64๋น„ํŠธ ์ •์ˆ˜๋ฅผ 32๋น„ํŠธ CPU์—์„œ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด, ์ด ์ž‘์—…์€ ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰˜์–ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ์ง€. ์ด๋•Œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋  ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜ฑ

์ผ๋ฐ˜ ์—ฐ์‚ฐ vs ์›์ž์  ์—ฐ์‚ฐ ์ผ๋ฐ˜ ์—ฐ์‚ฐ (count++) 1. ๋ฉ”๋ชจ๋ฆฌ์—์„œ count ๊ฐ’ ์ฝ๊ธฐ 2. count ๊ฐ’ ์ฆ๊ฐ€์‹œํ‚ค๊ธฐ 3. ์ฆ๊ฐ€๋œ ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ผ์–ด๋“ค ์ˆ˜ ์žˆ์Œ! ์›์ž์  ์—ฐ์‚ฐ (atomic_count++) ํ•œ ๋ฒˆ์— ์™„๋ฃŒ๋˜๋Š” ๋ถˆ๊ฐ€๋ถ„์˜ ์—ฐ์‚ฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ์ ‘๊ทผ ๋ถˆ๊ฐ€!

C++์—์„œ๋Š” std::atomic ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ด ์›์ž์  ํƒ€์ž…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ด ํƒ€์ž…์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ํ•ญ์ƒ ์›์ž์ ์œผ๋กœ ์ˆ˜ํ–‰๋ผ. ๐Ÿ‘

๐Ÿงช ์›์ž์  ํƒ€์ž… ์‚ฌ์šฉ ์˜ˆ์ œ

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> counter(0);  // ์›์ž์  ์นด์šดํ„ฐ ์„ ์–ธ

void increment_counter() {
    for (int i = 0; i < 1000; ++i) {
        counter++;  // ์›์ž์  ์ฆ๊ฐ€ ์—ฐ์‚ฐ
    }
}

int main() {
    std::thread t1(increment_counter);
    std::thread t2(increment_counter);
    
    t1.join();
    t2.join();
    
    std::cout << "์ตœ์ข… ์นด์šดํ„ฐ ๊ฐ’: " << counter << std::endl;  // ํ•ญ์ƒ 2000์ด ์ถœ๋ ฅ๋ผ
    return 0;
}

์›์ž์  ์—ฐ์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด:

  1. ๋ถˆ๊ฐ€๋ถ„์„ฑ(Indivisibility): ์—ฐ์‚ฐ์ด ์ค‘๊ฐ„์— ์ค‘๋‹จ๋˜์ง€ ์•Š์•„.
  2. ๊ฐ€์‹œ์„ฑ(Visibility): ํ•œ ์Šค๋ ˆ๋“œ์˜ ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณด์—ฌ.
  3. ์ˆœ์„œ ๋ณด์žฅ(Ordering): ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๊ทœ์น™์— ๋”ฐ๋ผ ์—ฐ์‚ฐ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋ผ.

C++์—์„œ ์ง€์›ํ•˜๋Š” ์ฃผ์š” ์›์ž์  ์—ฐ์‚ฐ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„:

์—ฐ์‚ฐ ์„ค๋ช… ์˜ˆ์ œ
load ์›์ž์ ์œผ๋กœ ๊ฐ’์„ ์ฝ์Œ int value = atomic_var.load();
store ์›์ž์ ์œผ๋กœ ๊ฐ’์„ ์ €์žฅ atomic_var.store(10);
exchange ๊ฐ’์„ ๊ต์ฒดํ•˜๊ณ  ์ด์ „ ๊ฐ’์„ ๋ฐ˜ํ™˜ int old = atomic_var.exchange(new_value);
compare_exchange ์กฐ๊ฑด๋ถ€ ๊ต์ฒด (CAS ์—ฐ์‚ฐ) atomic_var.compare_exchange_strong(expected, desired);
fetch_add, fetch_sub ๊ฐ’์„ ๋”ํ•˜๊ฑฐ๋‚˜ ๋นผ๊ณ  ์ด์ „ ๊ฐ’ ๋ฐ˜ํ™˜ int prev = atomic_var.fetch_add(5);
fetch_and, fetch_or, fetch_xor ๋น„ํŠธ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ด์ „ ๊ฐ’ ๋ฐ˜ํ™˜ int prev = atomic_var.fetch_and(mask);

๐Ÿ’ก ์•Œ์•„๋‘๋ฉด ์ข‹์€ ํŒ

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

4. ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ(Memory Ordering): ์ปดํ“จํ„ฐ์˜ ์ƒ๊ฐ ์ˆœ์„œ ์กฐ์ ˆํ•˜๊ธฐ ๐Ÿ”„

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

C++์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ์„ ์ œ๊ณตํ•ด:

C++ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ memory_order_seq_cst (์ˆœ์ฐจ์  ์ผ๊ด€์„ฑ) ๊ฐ€์žฅ ์—„๊ฒฉํ•˜๊ณ  ์ง๊ด€์ . ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์ผํ•œ ์ „์—ญ ์ˆœ์„œ๋ฅผ ๋ด„. (๊ธฐ๋ณธ๊ฐ’) memory_order_acq_rel (ํš๋“-ํ•ด์ œ) ํš๋“๊ณผ ํ•ด์ œ๋ฅผ ๋™์‹œ์— ์ˆ˜ํ–‰. ์–‘๋ฐฉํ–ฅ ๋™๊ธฐํ™”. memory_order_acquire (ํš๋“) ์ดํ›„ ์—ฐ์‚ฐ์ด ์ด์ „์œผ๋กœ ์ด๋™ ๋ชปํ•จ memory_order_release (ํ•ด์ œ) ์ด์ „ ์—ฐ์‚ฐ์ด ์ดํ›„๋กœ ์ด๋™ ๋ชปํ•จ memory_order_relaxed (์™„ํ™”๋จ) ์›์ž์„ฑ๋งŒ ๋ณด์žฅ. ์ˆœ์„œ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š์Œ. ๊ฐ€์žฅ ๋น ๋ฆ„. ์—„๊ฒฉํ•จ โ†‘ ์„ฑ๋Šฅ โ†“

๊ฐ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ ๋ชจ๋ธ์˜ ํŠน์ง•์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž:

1. memory_order_relaxed (์™„ํ™”๋จ) ๐Ÿƒโ€โ™‚๏ธ

๊ฐ€์žฅ ๋Š์Šจํ•œ ๋ชจ๋ธ. ์›์ž์„ฑ๋งŒ ๋ณด์žฅํ•˜๊ณ  ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์—ฐ์‚ฐ๊ณผ์˜ ์ˆœ์„œ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š์•„. ์„ฑ๋Šฅ์€ ๊ฐ€์žฅ ์ข‹์ง€๋งŒ, ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ€์žฅ ์–ด๋ ค์›Œ.

atomic_var.store(value, std::memory_order_relaxed);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋‹จ์ˆœ ์นด์šดํ„ฐ์ฒ˜๋Ÿผ ์ •ํ™•ํ•œ ๊ฐ’๋งŒ ์ค‘์š”ํ•˜๊ณ  ์ˆœ์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ.

2. memory_order_acquire (ํš๋“) ๐Ÿ”’

์ด ์—ฐ์‚ฐ ์ดํ›„์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ/์“ฐ๊ธฐ๊ฐ€ ์ด ์—ฐ์‚ฐ ์ด์ „์œผ๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ด. ์ฃผ๋กœ lock์„ ํš๋“ํ•  ๋•Œ ์‚ฌ์šฉ.

int value = atomic_var.load(std::memory_order_acquire);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋ฎคํ…์Šค ์ž ๊ธˆ ํš๋“, ๊ณต์œ  ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์ „ ๋™๊ธฐํ™”.

3. memory_order_release (ํ•ด์ œ) ๐Ÿ”“

์ด ์—ฐ์‚ฐ ์ด์ „์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ/์“ฐ๊ธฐ๊ฐ€ ์ด ์—ฐ์‚ฐ ์ดํ›„๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ด. ์ฃผ๋กœ lock์„ ํ•ด์ œํ•  ๋•Œ ์‚ฌ์šฉ.

atomic_var.store(value, std::memory_order_release);

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋ฎคํ…์Šค ์ž ๊ธˆ ํ•ด์ œ, ๊ณต์œ  ๋ฐ์ดํ„ฐ ์ˆ˜์ • ํ›„ ๋™๊ธฐํ™”.

4. memory_order_acq_rel (ํš๋“-ํ•ด์ œ) ๐Ÿ”„

ํš๋“๊ณผ ํ•ด์ œ์˜ ํŠน์„ฑ์„ ๋ชจ๋‘ ๊ฐ€์ง. ์›์ž์  ์ฝ๊ธฐ-์ˆ˜์ •-์“ฐ๊ธฐ(RMW) ์—ฐ์‚ฐ์— ์‚ฌ์šฉ.

old_value = atomic_var.fetch_add(1, std::memory_order_acq_rel);

์‚ฌ์šฉ ์‚ฌ๋ก€: ์›์ž์  ์—…๋ฐ์ดํŠธ์™€ ๋™์‹œ์— ์–‘๋ฐฉํ–ฅ ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ.

5. memory_order_seq_cst (์ˆœ์ฐจ์  ์ผ๊ด€์„ฑ) โš–๏ธ

๊ฐ€์žฅ ์—„๊ฒฉํ•œ ๋ชจ๋ธ๋กœ, ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋ชจ๋“  ์›์ž์  ์—ฐ์‚ฐ์˜ ๋™์ผํ•œ ์ˆœ์„œ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด. C++์—์„œ ๊ธฐ๋ณธ๊ฐ’์ด์•ผ.

atomic_var.store(value);  // ๊ธฐ๋ณธ๊ฐ’์€ memory_order_seq_cst

์‚ฌ์šฉ ์‚ฌ๋ก€: ์ง๊ด€์ ์ธ ๋™์ž‘์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ.

๐Ÿ” ์‹ค์ œ ์˜ˆ์ œ: ์ƒ์‚ฐ์ž-์†Œ๋น„์ž ํŒจํ„ด

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<bool> data_ready(false);
int shared_data;

void producer() {
    shared_data = 42;  // ๋ฐ์ดํ„ฐ ์ค€๋น„
    // release ์ˆœ์„œ: ์ด์ „ ์“ฐ๊ธฐ๊ฐ€ ์ด ์›์ž์  ์“ฐ๊ธฐ ์ดํ›„๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š์Œ
    data_ready.store(true, std::memory_order_release);
}

void consumer() {
    // acquire ์ˆœ์„œ: ์ด ์›์ž์  ์ฝ๊ธฐ๊ฐ€ ์ดํ›„ ์ฝ๊ธฐ ์•ž์œผ๋กœ ์žฌ๋ฐฐ์น˜๋˜์ง€ ์•Š์Œ
    while (!data_ready.load(std::memory_order_acquire)) {
        // ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
    }
    
    // ์ด์ œ shared_data๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ์Œ
    std::cout << "๊ณต์œ  ๋ฐ์ดํ„ฐ: " << shared_data << std::endl;  // ํ•ญ์ƒ 42 ์ถœ๋ ฅ
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    
    t1.join();
    t2.join();
    
    return 0;
}

์ด ์˜ˆ์ œ์—์„œ memory_order_release์™€ memory_order_acquire์˜ ์กฐํ•ฉ์€ ์ƒ์‚ฐ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์„ค์ •ํ•œ ํ›„์—๋งŒ ์†Œ๋น„์ž๊ฐ€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ด. ์ด๋Ÿฐ ํŒจํ„ด์„ "release-acquire ๋™๊ธฐํ™”"๋ผ๊ณ  ํ•ด.

๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์–ด. ํ™•์‹ ์ด ์—†๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์ธ memory_order_seq_cst๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•ด. ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ๋” ์™„ํ™”๋œ ๋ชจ๋ธ์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์–ด. ๐Ÿค”