NHN NEXT 1๊ธฐ
์ด์ง„์šฐ (jwlee@nhnnext.org)
Lock-free ์ž๋ฃŒ๊ตฌ์กฐ ์„ค๊ณ„
Chapter 7
blocking
โ€ข ์ž‘์—…์ด ๋๋‚  ๋•Œ ๊นŒ์ง€ ๋ฉˆ์ถ”๋Š” ๊ฒƒ์„ ๋œปํ•จ
โ€“ ๋๋‚  ๋•Œ ๊นŒ์ง€ ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ด ๋˜์ง€ ์•Š์Œ
โ€“ OS๊ฐ€ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์Œ (I/O ์ž‘์—… ๋“ฑ...)
โ€ข ์ž๋ฃŒ๊ตฌ์กฐ ๋ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ๋Š”,
โ€“ ๋ฎคํ…์Šค, ์ƒํƒœ๋ณ€์ˆ˜, std::future ๋“ฑ์„ ์“ฐ๋Š” ๊ฒฝ์šฐ
nonblocking ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ข…๋ฅ˜
โ€ข Obstruction-free
โ€“ ๋…๋ฆฝ์  ์‹คํ–‰ ์ค‘์—๋Š” ์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ
โ€ข Lock-free
โ€“ ์‹ค์งˆ์ ์œผ๋กœ (extreamly often)
์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ
โ€ข Wait-free
โ€“ ๋ฐ˜๋“œ์‹œ ํ•ญ์ƒ ์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ
๏ƒ  ์ถœ์ฒ˜ : The Art of Multiprocessor Programming
Spin-lock
โ€ข blocking ํ•จ์ˆ˜ ํ˜ธ์ถœ์€ ์—†๋‹ค
โ€ข lock-free๋Š” ์•„๋‹ˆ๋‹ค
...์ด๋Ÿฐ ์ƒํ™ฉ์ด ์ƒ๊ธฐ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
Thread 1
Thread 2 spin spin spin spin spin spinโ€ฆ
SpinLock์ž ๊ธˆ
์“ฐ๋ ˆ๋“œ suspend
Lock-free ์ž๋ฃŒ๊ตฌ์กฐ
โ€ข ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž๋ฃŒ๊ตฌ์กฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ
โ€“ ์ตœ์†Œํ•œ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋Š” ํ•ญ์ƒ ์ „์ง„ํ•จ์„ ๋ณด์žฅ
โ€“ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์ผํ•œ ์ž‘์—… ์ค‘ ๋ฉˆ์ท„์„ ๋•Œ
โ€ข ํ•ญ์ƒ ์„ฑ๊ณตํ•˜๋ฉด : lock-free
โ€ข ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์œผ๋ฉด : lock-free๊ฐ€ ์•„๋‹˜
โ€ข ๋„ˆ๋ฌด ๋งŽ์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒฝ์Ÿํ•˜๋ฉด?
โ€“ starvation ๋ฐœ์ƒ ๊ฐ€๋Šฅ
Wait-free ์ž๋ฃŒ๊ตฌ์กฐ
โ€ข ์ •ํ•ด์ง„ ์‹œ๋„ ํšŸ์ˆ˜ ์•ˆ์— ์™„๋ฃŒ
โ€“ ๋ฌดํ•œํžˆ ๋งŽ์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒฝ์Ÿ ํ•ด๋„ ์‹œ๊ฐ„ ๋‚ด ์™„๋ฃŒ
โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•ญ์ƒ ์ „์ง„ํ•จ์„ ๋ณด์žฅ
โ€ข ๊ตฌํ˜„์ด ๋งค์šฐ ์–ด๋ ต๋‹ค
โ€ข ์‹ค์งˆ์ ์œผ๋กœ ์„ฑ๋Šฅ์ด ์ข‹์ง€๋Š” ์•Š๋‹ค
Compare-and-swap
โ€ข ์ƒ๋‹น์ˆ˜์˜ Lock-free ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด CAS๋ฅผ ์‚ฌ์šฉ
โ€“ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” single-word CAS๋ฅผ ์˜๋ฏธ
โ€ข Double-word CAS
โ€“ 32bit ์‹œ์Šคํ…œ์—์„œ๋Š” 64bit CAS
โ€“ 64bit ์‹œ์Šคํ…œ์—์„œ๋Š” 128bit CAS
โ€“ ์ตœ์‹  CPU์—์„œ๋งŒ ์ผ๋ถ€ ์ง€์›
โ€“ ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ ์„ค์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ
Compare-and-swap
โ€ข C++11 ์—์„œ ๊ตฌํ˜„ ๋œ ํ˜•ํƒœ
โ€ข ์ฃผ์˜) ์ผ๋ฐ˜์ ์ธ CAS ์ธํ„ฐํŽ˜์ด์Šค์™€ ์•ฝ๊ฐ„ ๋‹ค๋ฆ„
โ€ข expected๊ฐ€ swap ์‹คํŒจ ์‹œ ์ตœ๊ทผ ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธ
โ€“ std::atomic<T>
(์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค)
Lock Free Stack ๊ตฌํ˜„
Stack
โ€ข ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„
stack::push()
Step 1 Step 2
A BN
Head
Step 3
N A
Head
B
B
N
Head
A
node ์ƒ์„ฑ
next ์„ค์ •
head ๋ณ€๊ฒฝ
stack::push()
Step 2 + race condition
A B
N
Head
X
๋ฌธ์ œ์ 
๏ƒ  Head๊ฐ€ ์ค‘๊ฐ„์— ๋ฐ”๋€Œ๋Š” ๋ฌธ์ œ
ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : Compare and swap
๏ƒ  Head๊ฐ€ ๋ฐ”๋€Œ๋ฉด Step 2,3 ์žฌ์‹œ๋„
stack::push()
โ€ข ๊ตฌํ˜„ ์ฝ”๋“œ
โ€“ node ์ƒ์„ฑ
โ€“ next ํฌ์ธํ„ฐ๋ฅผ ํ˜„์žฌ head๋กœ ์„ค์ •
โ€“ head ํฌ์ธํ„ฐ๋ฅผ node๋กœ ์„ค์ •
Race condition!
๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€
head ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
(1)
(2)
(3)
Lock-free stack::push()
โ€ข Lock-free ๊ตฌํ˜„
โ€“ head๊ฐ€ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ๋˜๋ฉด, ์‹คํŒจ ํ›„ ์žฌ์‹œ๋„
(1)
(2)
(3)
stack::pop()
Step 1 Step 2
BA
Head
B
Head
A
node node
(๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ํ•„์š”)
Lock-free stack::pop()
โ€ข ๊ตฌํ˜„ ๋ฐฉ์‹
โ€“ head ์ฝ๊ธฐ
โ€“ head๋ฅผ head๏ƒ next๋กœ ์„ค์ •
โ€“ ํš๋“ํ•œ node์—์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
stack::pop() ๋ฌธ์ œ์  #1
โ€ข ๋ฌธ์ œ์  1
โ€“ ์Šคํƒ์ด ๋น„์–ด์žˆ์„ ๋•Œ NULL ์ฐธ์กฐ
โ€“ ์ €์žฅ ๊ฐ’์„ ํฌ์ธํ„ฐ๋กœ ๋ฐ”๊พธ๊ณ , old_head ์ฒดํฌ
stack::pop() ๋ฌธ์ œ์  #2
โ€ข ๋ฌธ์ œ์  2
โ€“ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ (node๋ฅผ delete ํ•˜์ง€ ์•Š์Œ)
โ€“ delete ๋˜๋ฉด, ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ๋ฐ ABA ๋ฌธ์ œ ๋ฐœ์ƒ
โ€“ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ(reclaim) ๊ธฐ๋ฒ• ํ•„์š”
ํ•ด์ œ ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ์œ„ํ—˜
๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ delete ๋˜๋ฉด?
ABA ๋ฌธ์ œ
B
Head
A
C
Head
A
(1) pop ์ค‘์ธ ์“ฐ๋ ˆ๋“œ :
์ฃผ์†Œ A์™€ B ํ™•์ธ,
head.CAS( A ๏ƒ  B )
ํ•จ์ˆ˜ ํ˜ธ์ถœ
(2) ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ :
A, B pop,
์ดํ›„ A push
(์‹œ๊ฐ„)
C
Head
A
(3) pop ์ค‘์ธ ์“ฐ๋ ˆ๋“œ :
head.CAS( A ๏ƒ  B )
ํ•จ์ˆ˜ ์‹คํ–‰
์ฃผ์†Œ A๋ฅผ delete ํ•œ ์ดํ›„,
new๋กœ A๋ฅผ ๋‹ค์‹œ ํ• ๋‹น ๊ฐ€๋Šฅ
B??
๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ• #1
โ€ข ํ™€๋กœ ์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ชฐ์•„์„œ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ ์ˆ˜
์“ฐ๋ ˆ๋“œ ์ˆ˜ ์ฒดํฌ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ
โ€ข ๊ฐœ๋…์ ์ธ ์ฒ˜๋ฆฌ ๊ณผ์ •
ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ
โ€ข ๊ฐœ๋…์ ์ธ ์ฒ˜๋ฆฌ ๊ณผ์ • (๊ฐœ์„  ๋œ ๋ฒ„์ „)
ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ
โ€ข ๊ตฌํ˜„ ์ฝ”๋“œ
๋ฆฌ์ŠคํŠธ์— ๋ณ‘ํ•ฉํ•˜๋„๋ก
๊ตฌํ˜„๋œ๋‹ค
Null๋กœ ๋งŒ๋“ค์ง€๋งŒ,
๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ
์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ
๋” ์ž์„ธํ•œ ์ฝ”๋“œ๋Š” ์ฑ…์—...
ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ
โ€ข ๋‹จ์ 
โ€“ Starvation ๋ฐœ์ƒ ๊ฐ€๋Šฅ
โ€“ ์‚ญ์ œ ๋Œ€๊ธฐ ์ค‘์ธ ๋…ธ๋“œ๊ฐ€ ๋ฌดํ•œ์ • ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ• #2
โ€ข ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€“ ์ž ์žฌ์ ์ธ ์œ„ํ—˜์„ ๊ฐ€์ง„ ํฌ์ธํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋ฒ•
โ€“ ์—์„œ ํŠนํ—ˆ ์†Œ์œ 
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ์„ค์ •
Pop (CAS)
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ํ•ด์ œ
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ์ฒดํฌ
์ง€๊ธˆ ์‚ญ์ œ ๋‚˜์ค‘์— ์‚ญ์ œ
ํ…Œ์ด๋ธ” ์ฒดํฌ & ์‚ญ์ œ
Step 1 Step 2
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€ข ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ์„ค์ • ๋ฐฉ์‹
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ(hp)์—
๋“ค์–ด๊ฐ„ ์‹œ์ ์—์„œ
์ง€์›Œ์ง€์ง€ ์•Š์•˜์Œ์„
๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ˜๋ณต๋ฌธ
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€ข ํ•ด์ €๋“œ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ stack::pop() ๊ตฌํ˜„
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ๋กœ
๊ด€๋ฆฌ๋˜๋Š” ๋ถ€๋ถ„
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€ข ํ•ด์ €๋“œ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ stack::pop() ๊ตฌํ˜„
ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€ข ์žฅ์ 
โ€“ Starvation์ด ์ƒ๊ธฐ์ง€ ์•Š์Œ
โ€ข ๋‹จ์ 
โ€“ ํฌ์ธํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ํ…Œ์ด๋ธ”(์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ) ์‚ฌ์šฉ
โ€“ ํฌ์ธํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ํ…Œ์ด๋ธ” ๊ฐœ์ˆ˜์˜ ํ•œ๊ณ„
โ€“ ํŠนํ—ˆ๊ฐ€ ์žˆ๋‹ค.
๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ• #3
โ€ข Reference counting
โ€“ std::shared_ptr<T> :
โ€ข ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๋ฅผ ์•Œ์•„์„œ ํ•ด ์ค€๋‹ค.
shared_ptr ์‚ฌ์šฉํ•œ lock-free stack
์•ˆํƒ€๊น๊ฒŒ๋„ ์ฑ…์— ์žˆ๋Š” ์ฝ”๋“œ๋Š” FAIL
Double-word CAS
โ€ข std::shared_ptr<T>๋Š” double-word
โ€“ double-word CAS๋ฅผ ์ง€์›ํ•˜๋ฉด ํ•ด๊ฒฐ๋จ
โ€“ ๋‹คํ–‰ํžˆ ์ตœ์‹  CPU ์—์„œ๋Š” 128-bit CAS ์ง€์›
โ€ข CPU์—์„œ ์ง€์›๋˜์ง€ ์•Š์œผ๋ฉด?
โ€“ ๋Œ€์•ˆ : ํฌ์ธํ„ฐ ์••์ถ• ํ…Œํฌ๋‹‰
โ€“ 64bit ํฌ์ธํ„ฐ์˜ ์ผ๋ถ€๋ฅผ ๋‹ค๋ฅธ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ
Double-word CAS
โ€ข ์ปดํŒŒ์ผ๋Ÿฌ์˜ std::atomic<T> ์ง€์› ์—ฌ๋ถ€
โ€“ is_lock_free()๋Š” 128bit ์—์„œ false
โ€“ std::shared_ptr<T> ๋Š”
not trivially copyable ๋ผ์„œ atomic์— ์‚ฌ์šฉ๋ถˆ๊ฐ€
โ€ข ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ์ง€์›๋˜์ง€ ์•Š์œผ๋ฉด?
โ€“ ๋Œ€์•ˆ : ์ „๋ถ€ ์ง์ ‘ ๊ตฌํ˜„
128-bit CAS ๊ตฌํ˜„
โ€ข CMPXCHG16B
128-bit CAS ๊ตฌํ˜„
โ€ข VC++ : _InterlockedCompareExchange128()
128-bit CAS ๊ตฌํ˜„
cmpxchg16b
Reference counting ์ง์ ‘ ๊ตฌํ˜„
Split Reference Count
โ€ข external count
โ€“ ์ดˆ๊ธฐ๊ฐ’ : 0
โ€“ pop ์‹œ๋„ ์ „ ์ฆ๊ฐ€
โ€ข internal count
โ€“ ์ดˆ๊ธฐ๊ฐ’ : 0
โ€“ pop ์‹œ๋„ ํ›„ 1 ๊ฐ์†Œ
node
data
internal_count
counted_node_ptr
counted_node_ptr
external_count
ptr
Split Reference Count
โ€ข pop() ์„ฑ๊ณต ํ›„
โ€“ Pop์„ ์„ฑ๊ณตํ•œ ์“ฐ๋ ˆ๋“œ๋Š”,
โ€“ ์ตœ์ข… external_count ํ™•๋ณด,
โ€“ internal_count ์— atomic_add
โ€ข pop() ์‹œ๋„ ์ดํ›„ (์„ฑ๊ณต / ์‹คํŒจ ์—ฌ๋ถ€ ์ƒ๊ด€์—†์ด)
โ€“ internal_count ๊ฐ์†Œ ํ›„ 0๋ฉด ๋…ธ๋“œ ์‚ญ์ œ
external_count +1 external_count +1
pop ์„ฑ๊ณต pop ์‹คํŒจ
internal_count -1
internal_count +n
Split Reference Count
โ€ข ์‚ญ์ œ ์ง€์—ฐ Case 1
< 0
= 0, delete
external_count +1 external_count +1
pop ์„ฑ๊ณต pop ์‹คํŒจ
internal_count +n
internal_count -1
Split Reference Count
โ€ข ์‚ญ์ œ ์ง€์—ฐ Case 2
= 0, delete
> 0
Lock Free Stack ์ •๋ฆฌ
โ€ข CAS๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„
โ€ข ์–ด๋ ค์šด ๋ถ€๋ถ„ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ
โ€“ ๋ชฐ์•„์„œ ํ•ด์ œ
โ€“ ํ•ด์ €๋“œ ํฌ์ธํ„ฐ
โ€“ ๋ ˆํผ๋Ÿฐ์Šค ์นด์šดํŒ…
โ€ข Double-word CAS ์ง€์› ๋ฌธ์ œ
โ€ข std::shared_ptr์˜ atomic ์ง€์› ๋ฌธ์ œ
โ€ข ์ง์ ‘ ๊ตฌํ˜„
๊ธฐํƒ€ ์ตœ์ ํ™”
โ€ข Atomic operation ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์ตœ์ ํ™”
โ€“ ์•„์ง๊นŒ์ง€๋Š” Memory model ๊ณ ๋ คํ•˜์ง€ ์•Š์Œ
โ€“ ๊ธฐ๋ณธ ๊ฐ’ : memory_order_seq_cst
๏ƒ  ์ ์ ˆํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๋กœ ๋ณ€๊ฒฝ
โ€ข _InterlockedCompareExchange128
โ€“ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์„ค์ • ๋ถˆ๊ฐ€
Lock Free Queue ๊ตฌํ˜„
Queue
โ€ข ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„
๊ฐœ๋… ์ดํ•ด๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ
(์›๋ž˜๋Š” shared_ptr๋ฅผ ์”๋‹ˆ๋‹ค)
Queue
โ€ข ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„
DC
Tail
B
Head
A
pop push
Queue ์˜ ๊ตฌ๋ถ„
โ€ข Single-producer (SP)
โ€ข Multi-producer (MP)
โ€ข Single-consumer (SC)
โ€ข Multi-consumer (MC)
โ€ข ์ œ์•ฝ ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ
โ€“ SPSC, SPMC, MPSC, MPMC ๋กœ ๊ตฌ๋ถ„
์ด๊ฑด ์‰ฌ์›€
Queue
โ€ข Thread๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์€ ๋‹จ์ˆœ ๊ตฌํ˜„
๋น„์–ด ์žˆ์„ ๋•Œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•˜๋‚˜ ์žˆ์„ ๋•Œ๋„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
์ด๋ฏธ ๋ญ”๊ฐ€ ๋ณต์žกํ•˜๋‹ค?
์ด ๋ฐฉ์‹์„ lock-free๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ๋Š” ํž˜๋“ฆ..
๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Queue
โ€“ Head์™€ Tail์€ ํ•ญ์ƒ null์ด ์•„๋‹˜
โ€“ pop(), push() ๊ตฌํ˜„์ด ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
/C
Tail
B
Head
A
๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Queue
โ€ข push()
โ€“ ๋”๋ฏธ ๋…ธ๋“œ์— ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ ๏ƒ  ์‹ค์ œ node๊ฐ€ ๋จ
โ€“ ์ดํ›„ ์ƒˆ๋กœ์šด ๋”๋ฏธ ๋…ธ๋“œ ์ƒ์„ฑ
๏ƒ  Head๋ฅผ ์ˆ˜์ • ํ•  ํ•„์š”๊ฐ€ ์—†์Œ
/C
Tail
B
Head
A
๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Queue
โ€ข pop()
โ€“ Head != Tail ์ธ ๊ฒฝ์šฐ์—๋งŒ pop()
โ€“ Tail์„ ์ˆ˜์ • ํ•  ํ•„์š”๊ฐ€ ์—†์Œ
/C
Tail
B
Head
A
SPSC Lock-free Queue
โ€ข Push ๊ตฌํ˜„
โ€“ tail ํฌ์ธํ„ฐ๋ฅผ atomic ์œผ๋กœ ๊ตฌํ˜„
โ€“ (1)์—์„œ ๋”๋ฏธ ๋…ธ๋“œ์— ๋ฐ์ดํ„ฐ ๋„ฃ์Œ
(1)
(2)
SPSC Lock-free Queue
โ€ข Pop ๊ตฌํ˜„
โ€“ (3) ์ด (2)์™€ synchronized-with ๊ด€๊ณ„
โ€“ ์—ฌ๊ธฐ๊นŒ์ง€๋Š” SPSC์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ๋™์ž‘
(3)
Multi-consumer pop()
โ€ข Head != Tail ์ฒดํฌ ํ›„ CAS๋กœ pop ์‹œ๋„ ๋ฐ˜๋ณต
โ€ข ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ
โ€“ ์Šคํƒ ๊ตฌํ˜„์—์„œ ์ด๋ฏธ ๋‹ค๋ฃฌ ๋ฌธ์ œ
(์ฑ…์—์„œ๋Š” ์Šคํƒ์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ Split Reference Count๋กœ ์ง„ํ–‰)
Multi-producer push()
/
Tail
B
Head
A
C
/C
Tail
B
Head
A
1) CAS๋กœ ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€
2) ์ƒˆ ๋…ธ๋“œ ์ถ”๊ฐ€
3) Tail ๋ณ€๊ฒฝ
๋ฌธ์ œ์  #1 : CAS ์‹œ์ ์˜ tail
โ€ข CAS ์‹œ์ ์— Tail์ด ํ•ด์ œ ๋˜์—ˆ์„ ์ˆ˜ ์žˆ๋‹ค.
์ด ์‹œ์ ์—์„œ
๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ
Push ๏ƒ  Pop
์ผ์–ด๋‚˜๋ฉด
old_tail
์‚ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ
Split Reference Count
โ€ข tail ๋„ counted_node_ptr๋กœ ๊ตฌํ˜„
โ€ข counted_node_ptr์˜ ๊ฐœ์ˆ˜๋ฅผ ์ฒดํฌ
/C
Tail
B
Head
A
Split Reference Count
โ€ข external count
โ€“ ์ตœ๋Œ€ 2๊ฐœ
โ€ข internal count
โ€ข external_counters
counted_node_ptr
external_count
ptr
counted_node_ptr
external_count
ptr
node
data
internal_count
counted_node_ptr
ext_counters = 2
๋ฌธ์ œ์  #2 : Blocking
โ€ข Push ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„...
โ€“ ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ ํ•œ ์ƒํƒœ์—์„œ,
โ€“ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„๋งŒ ๋ฐ˜๋ณตํ•˜๋ฉด?
โ€ข ๊ณ„์† ์‹คํŒจ, lock-free๊ฐ€ ์•„๋‹ˆ๊ฒŒ ๋จ
DC
Tail
B
Head
A
Blocking ๋ฌธ์ œ ํ•ด๊ฒฐ
โ€ข Tail node์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€ ๋˜์—ˆ์„ ๋•Œ
โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒˆ dummy node ์ถ”๊ฐ€ ์‹œ๋„
โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒˆ ๋…ธ๋“œ๋กœ Tail ๋ณ€๊ฒฝ ์‹œ๋„
์ฑ…์„ ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
(์–ด๋ ค์šฐ๋‹ˆ ๊ฐ์˜คํ•˜์‹œ๊ณ ..)
Lock Free Queue ์ •๋ฆฌ
โ€ข CAS๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„
โ€ข ์–ด๋ ค์šด ๋ถ€๋ถ„ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ
โ€“ ์Šคํƒ๊ณผ ๊ทผ๋ณธ์ ์œผ๋กœ๋Š” ๊ฐ™์€ ๋ฌธ์ œ
โ€“ Tail ์ฒ˜๋ฆฌ ๊ตฌํ˜„ ์ค‘ ์ถ”๊ฐ€๋กœ ํŒŒ์ƒ๋˜๋Š” ๋ฌธ์ œ
โ€ข ABA ๋ฌธ์ œ
โ€ข Blocking ( busy-waiting ) ๋ฌธ์ œ
์ด์ •๋ฆฌ
โ€ข Lock-free ์ž๋ฃŒ๊ตฌ์กฐ ์ž‘์„ฑ ์š”๋ น
โ€“ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ๊ณ ๋ คํ•˜์ง€๋Š” ์•Š์Œ
โ€ข ์ด๋ฏธ ์ถฉ๋ถ„ํžˆ ์–ด๋ ค์šฐ๋‹ˆ๊นŒ
โ€“ Lock-free ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ•๋“ค ์ ์šฉ
โ€ข stack ๊ตฌํ˜„์—์„œ ์ œ์‹œํ•œ ์„ธ ๊ฐ€์ง€ ๊ธฐ๋ฒ•
โ€“ ABA ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ณ ๋ ค ํ•„์š”
โ€“ Busy-waiting์„ ์ธ์ง€ํ•˜๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ ์ผ ํ•ด์ฃผ๊ธฐ
โ€ข ๋ˆ„๊ฐ€ ์‹œ์ž‘ํ–ˆ๋˜ ๋ฉˆ์ถ”๋ฉด ์•ˆ๋จ
๊ฒฐ๋ก 
โ€ข ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค
โ€ข ๋Œ€์•ˆ
โ€“ ์ž˜ ๊ตฌํ˜„๋œ ๊ตฌํ˜„์ฒด ( boost, intel TBB ๋“ฑ ) ์‚ฌ์šฉ
โ€“ MPSC ํ˜•ํƒœ ์ฒ˜๋Ÿผ ์ œ์•ฝ์„ ์ฃผ๋Š” ํ˜•ํƒœ๋กœ ๊ตฌํ˜„
โ€“ Java๋‚˜ C# ์‚ฌ์šฉ...

Concurrency in action - chapter 7

  • 1.
    NHN NEXT 1๊ธฐ ์ด์ง„์šฐ(jwlee@nhnnext.org) Lock-free ์ž๋ฃŒ๊ตฌ์กฐ ์„ค๊ณ„ Chapter 7
  • 2.
    blocking โ€ข ์ž‘์—…์ด ๋๋‚ ๋•Œ ๊นŒ์ง€ ๋ฉˆ์ถ”๋Š” ๊ฒƒ์„ ๋œปํ•จ โ€“ ๋๋‚  ๋•Œ ๊นŒ์ง€ ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ด ๋˜์ง€ ์•Š์Œ โ€“ OS๊ฐ€ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์Œ (I/O ์ž‘์—… ๋“ฑ...) โ€ข ์ž๋ฃŒ๊ตฌ์กฐ ๋ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ๋Š”, โ€“ ๋ฎคํ…์Šค, ์ƒํƒœ๋ณ€์ˆ˜, std::future ๋“ฑ์„ ์“ฐ๋Š” ๊ฒฝ์šฐ
  • 3.
    nonblocking ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ข…๋ฅ˜ โ€ขObstruction-free โ€“ ๋…๋ฆฝ์  ์‹คํ–‰ ์ค‘์—๋Š” ์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ โ€ข Lock-free โ€“ ์‹ค์งˆ์ ์œผ๋กœ (extreamly often) ์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ โ€ข Wait-free โ€“ ๋ฐ˜๋“œ์‹œ ํ•ญ์ƒ ์ผ์ • ์Šคํ… ์•ˆ์— ์ข…๋ฃŒ ๋ณด์žฅ ๏ƒ  ์ถœ์ฒ˜ : The Art of Multiprocessor Programming
  • 4.
    Spin-lock โ€ข blocking ํ•จ์ˆ˜ํ˜ธ์ถœ์€ ์—†๋‹ค โ€ข lock-free๋Š” ์•„๋‹ˆ๋‹ค ...์ด๋Ÿฐ ์ƒํ™ฉ์ด ์ƒ๊ธฐ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. Thread 1 Thread 2 spin spin spin spin spin spinโ€ฆ SpinLock์ž ๊ธˆ ์“ฐ๋ ˆ๋“œ suspend
  • 5.
    Lock-free ์ž๋ฃŒ๊ตฌ์กฐ โ€ข ๋‹ค์ˆ˜์˜์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž๋ฃŒ๊ตฌ์กฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ โ€“ ์ตœ์†Œํ•œ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋Š” ํ•ญ์ƒ ์ „์ง„ํ•จ์„ ๋ณด์žฅ โ€“ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์ผํ•œ ์ž‘์—… ์ค‘ ๋ฉˆ์ท„์„ ๋•Œ โ€ข ํ•ญ์ƒ ์„ฑ๊ณตํ•˜๋ฉด : lock-free โ€ข ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์œผ๋ฉด : lock-free๊ฐ€ ์•„๋‹˜ โ€ข ๋„ˆ๋ฌด ๋งŽ์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒฝ์Ÿํ•˜๋ฉด? โ€“ starvation ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • 6.
    Wait-free ์ž๋ฃŒ๊ตฌ์กฐ โ€ข ์ •ํ•ด์ง„์‹œ๋„ ํšŸ์ˆ˜ ์•ˆ์— ์™„๋ฃŒ โ€“ ๋ฌดํ•œํžˆ ๋งŽ์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒฝ์Ÿ ํ•ด๋„ ์‹œ๊ฐ„ ๋‚ด ์™„๋ฃŒ โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•ญ์ƒ ์ „์ง„ํ•จ์„ ๋ณด์žฅ โ€ข ๊ตฌํ˜„์ด ๋งค์šฐ ์–ด๋ ต๋‹ค โ€ข ์‹ค์งˆ์ ์œผ๋กœ ์„ฑ๋Šฅ์ด ์ข‹์ง€๋Š” ์•Š๋‹ค
  • 7.
    Compare-and-swap โ€ข ์ƒ๋‹น์ˆ˜์˜ Lock-free์•Œ๊ณ ๋ฆฌ์ฆ˜์ด CAS๋ฅผ ์‚ฌ์šฉ โ€“ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” single-word CAS๋ฅผ ์˜๋ฏธ โ€ข Double-word CAS โ€“ 32bit ์‹œ์Šคํ…œ์—์„œ๋Š” 64bit CAS โ€“ 64bit ์‹œ์Šคํ…œ์—์„œ๋Š” 128bit CAS โ€“ ์ตœ์‹  CPU์—์„œ๋งŒ ์ผ๋ถ€ ์ง€์› โ€“ ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ ์„ค์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ
  • 8.
    Compare-and-swap โ€ข C++11 ์—์„œ๊ตฌํ˜„ ๋œ ํ˜•ํƒœ โ€ข ์ฃผ์˜) ์ผ๋ฐ˜์ ์ธ CAS ์ธํ„ฐํŽ˜์ด์Šค์™€ ์•ฝ๊ฐ„ ๋‹ค๋ฆ„ โ€ข expected๊ฐ€ swap ์‹คํŒจ ์‹œ ์ตœ๊ทผ ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธ โ€“ std::atomic<T> (์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค)
  • 9.
    Lock Free Stack๊ตฌํ˜„
  • 10.
  • 11.
    stack::push() Step 1 Step2 A BN Head Step 3 N A Head B B N Head A node ์ƒ์„ฑ next ์„ค์ • head ๋ณ€๊ฒฝ
  • 12.
    stack::push() Step 2 +race condition A B N Head X ๋ฌธ์ œ์  ๏ƒ  Head๊ฐ€ ์ค‘๊ฐ„์— ๋ฐ”๋€Œ๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : Compare and swap ๏ƒ  Head๊ฐ€ ๋ฐ”๋€Œ๋ฉด Step 2,3 ์žฌ์‹œ๋„
  • 13.
    stack::push() โ€ข ๊ตฌํ˜„ ์ฝ”๋“œ โ€“node ์ƒ์„ฑ โ€“ next ํฌ์ธํ„ฐ๋ฅผ ํ˜„์žฌ head๋กœ ์„ค์ • โ€“ head ํฌ์ธํ„ฐ๋ฅผ node๋กœ ์„ค์ • Race condition! ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ head ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ (1) (2) (3)
  • 14.
    Lock-free stack::push() โ€ข Lock-free๊ตฌํ˜„ โ€“ head๊ฐ€ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ๋˜๋ฉด, ์‹คํŒจ ํ›„ ์žฌ์‹œ๋„ (1) (2) (3)
  • 15.
    stack::pop() Step 1 Step2 BA Head B Head A node node (๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ํ•„์š”)
  • 16.
    Lock-free stack::pop() โ€ข ๊ตฌํ˜„๋ฐฉ์‹ โ€“ head ์ฝ๊ธฐ โ€“ head๋ฅผ head๏ƒ next๋กœ ์„ค์ • โ€“ ํš๋“ํ•œ node์—์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
  • 17.
    stack::pop() ๋ฌธ์ œ์  #1 โ€ข๋ฌธ์ œ์  1 โ€“ ์Šคํƒ์ด ๋น„์–ด์žˆ์„ ๋•Œ NULL ์ฐธ์กฐ โ€“ ์ €์žฅ ๊ฐ’์„ ํฌ์ธํ„ฐ๋กœ ๋ฐ”๊พธ๊ณ , old_head ์ฒดํฌ
  • 18.
    stack::pop() ๋ฌธ์ œ์  #2 โ€ข๋ฌธ์ œ์  2 โ€“ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ (node๋ฅผ delete ํ•˜์ง€ ์•Š์Œ) โ€“ delete ๋˜๋ฉด, ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ๋ฐ ABA ๋ฌธ์ œ ๋ฐœ์ƒ โ€“ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ(reclaim) ๊ธฐ๋ฒ• ํ•„์š” ํ•ด์ œ ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ์œ„ํ—˜ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ delete ๋˜๋ฉด?
  • 19.
    ABA ๋ฌธ์ œ B Head A C Head A (1) pop์ค‘์ธ ์“ฐ๋ ˆ๋“œ : ์ฃผ์†Œ A์™€ B ํ™•์ธ, head.CAS( A ๏ƒ  B ) ํ•จ์ˆ˜ ํ˜ธ์ถœ (2) ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ : A, B pop, ์ดํ›„ A push (์‹œ๊ฐ„) C Head A (3) pop ์ค‘์ธ ์“ฐ๋ ˆ๋“œ : head.CAS( A ๏ƒ  B ) ํ•จ์ˆ˜ ์‹คํ–‰ ์ฃผ์†Œ A๋ฅผ delete ํ•œ ์ดํ›„, new๋กœ A๋ฅผ ๋‹ค์‹œ ํ• ๋‹น ๊ฐ€๋Šฅ B??
  • 20.
    ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ•#1 โ€ข ํ™€๋กœ ์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ชฐ์•„์„œ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ ์ˆ˜ ์“ฐ๋ ˆ๋“œ ์ˆ˜ ์ฒดํฌ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
  • 21.
    ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ โ€ข๊ฐœ๋…์ ์ธ ์ฒ˜๋ฆฌ ๊ณผ์ •
  • 22.
    ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ โ€ข๊ฐœ๋…์ ์ธ ์ฒ˜๋ฆฌ ๊ณผ์ • (๊ฐœ์„  ๋œ ๋ฒ„์ „)
  • 23.
    ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ โ€ข๊ตฌํ˜„ ์ฝ”๋“œ ๋ฆฌ์ŠคํŠธ์— ๋ณ‘ํ•ฉํ•˜๋„๋ก ๊ตฌํ˜„๋œ๋‹ค Null๋กœ ๋งŒ๋“ค์ง€๋งŒ, ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋” ์ž์„ธํ•œ ์ฝ”๋“œ๋Š” ์ฑ…์—...
  • 24.
    ํ•œ๋ฒˆ์— ๋ชฐ์•„์„œ ํ•ด์ œ โ€ข๋‹จ์  โ€“ Starvation ๋ฐœ์ƒ ๊ฐ€๋Šฅ โ€“ ์‚ญ์ œ ๋Œ€๊ธฐ ์ค‘์ธ ๋…ธ๋“œ๊ฐ€ ๋ฌดํ•œ์ • ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
  • 25.
    ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ•#2 โ€ข ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€“ ์ž ์žฌ์ ์ธ ์œ„ํ—˜์„ ๊ฐ€์ง„ ํฌ์ธํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋ฒ• โ€“ ์—์„œ ํŠนํ—ˆ ์†Œ์œ  ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ์„ค์ • Pop (CAS) ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ํ•ด์ œ ํ•ด์ €๋“œ ํฌ์ธํ„ฐ ์ฒดํฌ ์ง€๊ธˆ ์‚ญ์ œ ๋‚˜์ค‘์— ์‚ญ์ œ ํ…Œ์ด๋ธ” ์ฒดํฌ & ์‚ญ์ œ Step 1 Step 2
  • 26.
    ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€ข ํ•ด์ €๋“œํฌ์ธํ„ฐ ์„ค์ • ๋ฐฉ์‹ ํ•ด์ €๋“œ ํฌ์ธํ„ฐ(hp)์— ๋“ค์–ด๊ฐ„ ์‹œ์ ์—์„œ ์ง€์›Œ์ง€์ง€ ์•Š์•˜์Œ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ˜๋ณต๋ฌธ
  • 27.
    ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€ข ํ•ด์ €๋“œํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ stack::pop() ๊ตฌํ˜„ ํ•ด์ €๋“œ ํฌ์ธํ„ฐ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋ถ€๋ถ„
  • 28.
    ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€ข ํ•ด์ €๋“œํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ stack::pop() ๊ตฌํ˜„
  • 29.
    ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€ข ์žฅ์  โ€“Starvation์ด ์ƒ๊ธฐ์ง€ ์•Š์Œ โ€ข ๋‹จ์  โ€“ ํฌ์ธํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ํ…Œ์ด๋ธ”(์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ) ์‚ฌ์šฉ โ€“ ํฌ์ธํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ํ…Œ์ด๋ธ” ๊ฐœ์ˆ˜์˜ ํ•œ๊ณ„ โ€“ ํŠนํ—ˆ๊ฐ€ ์žˆ๋‹ค.
  • 30.
    ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ•#3 โ€ข Reference counting โ€“ std::shared_ptr<T> : โ€ข ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๋ฅผ ์•Œ์•„์„œ ํ•ด ์ค€๋‹ค.
  • 31.
    shared_ptr ์‚ฌ์šฉํ•œ lock-freestack ์•ˆํƒ€๊น๊ฒŒ๋„ ์ฑ…์— ์žˆ๋Š” ์ฝ”๋“œ๋Š” FAIL
  • 32.
    Double-word CAS โ€ข std::shared_ptr<T>๋Š”double-word โ€“ double-word CAS๋ฅผ ์ง€์›ํ•˜๋ฉด ํ•ด๊ฒฐ๋จ โ€“ ๋‹คํ–‰ํžˆ ์ตœ์‹  CPU ์—์„œ๋Š” 128-bit CAS ์ง€์› โ€ข CPU์—์„œ ์ง€์›๋˜์ง€ ์•Š์œผ๋ฉด? โ€“ ๋Œ€์•ˆ : ํฌ์ธํ„ฐ ์••์ถ• ํ…Œํฌ๋‹‰ โ€“ 64bit ํฌ์ธํ„ฐ์˜ ์ผ๋ถ€๋ฅผ ๋‹ค๋ฅธ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ
  • 33.
    Double-word CAS โ€ข ์ปดํŒŒ์ผ๋Ÿฌ์˜std::atomic<T> ์ง€์› ์—ฌ๋ถ€ โ€“ is_lock_free()๋Š” 128bit ์—์„œ false โ€“ std::shared_ptr<T> ๋Š” not trivially copyable ๋ผ์„œ atomic์— ์‚ฌ์šฉ๋ถˆ๊ฐ€ โ€ข ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ์ง€์›๋˜์ง€ ์•Š์œผ๋ฉด? โ€“ ๋Œ€์•ˆ : ์ „๋ถ€ ์ง์ ‘ ๊ตฌํ˜„
  • 34.
  • 35.
    128-bit CAS ๊ตฌํ˜„ โ€ขVC++ : _InterlockedCompareExchange128()
  • 36.
  • 37.
  • 38.
    Split Reference Count โ€ขexternal count โ€“ ์ดˆ๊ธฐ๊ฐ’ : 0 โ€“ pop ์‹œ๋„ ์ „ ์ฆ๊ฐ€ โ€ข internal count โ€“ ์ดˆ๊ธฐ๊ฐ’ : 0 โ€“ pop ์‹œ๋„ ํ›„ 1 ๊ฐ์†Œ node data internal_count counted_node_ptr counted_node_ptr external_count ptr
  • 39.
    Split Reference Count โ€ขpop() ์„ฑ๊ณต ํ›„ โ€“ Pop์„ ์„ฑ๊ณตํ•œ ์“ฐ๋ ˆ๋“œ๋Š”, โ€“ ์ตœ์ข… external_count ํ™•๋ณด, โ€“ internal_count ์— atomic_add โ€ข pop() ์‹œ๋„ ์ดํ›„ (์„ฑ๊ณต / ์‹คํŒจ ์—ฌ๋ถ€ ์ƒ๊ด€์—†์ด) โ€“ internal_count ๊ฐ์†Œ ํ›„ 0๋ฉด ๋…ธ๋“œ ์‚ญ์ œ
  • 40.
    external_count +1 external_count+1 pop ์„ฑ๊ณต pop ์‹คํŒจ internal_count -1 internal_count +n Split Reference Count โ€ข ์‚ญ์ œ ์ง€์—ฐ Case 1 < 0 = 0, delete
  • 41.
    external_count +1 external_count+1 pop ์„ฑ๊ณต pop ์‹คํŒจ internal_count +n internal_count -1 Split Reference Count โ€ข ์‚ญ์ œ ์ง€์—ฐ Case 2 = 0, delete > 0
  • 42.
    Lock Free Stack์ •๋ฆฌ โ€ข CAS๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ โ€ข ์–ด๋ ค์šด ๋ถ€๋ถ„ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ โ€“ ๋ชฐ์•„์„œ ํ•ด์ œ โ€“ ํ•ด์ €๋“œ ํฌ์ธํ„ฐ โ€“ ๋ ˆํผ๋Ÿฐ์Šค ์นด์šดํŒ… โ€ข Double-word CAS ์ง€์› ๋ฌธ์ œ โ€ข std::shared_ptr์˜ atomic ์ง€์› ๋ฌธ์ œ โ€ข ์ง์ ‘ ๊ตฌํ˜„
  • 43.
    ๊ธฐํƒ€ ์ตœ์ ํ™” โ€ข Atomicoperation ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์ตœ์ ํ™” โ€“ ์•„์ง๊นŒ์ง€๋Š” Memory model ๊ณ ๋ คํ•˜์ง€ ์•Š์Œ โ€“ ๊ธฐ๋ณธ ๊ฐ’ : memory_order_seq_cst ๏ƒ  ์ ์ ˆํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๋กœ ๋ณ€๊ฒฝ โ€ข _InterlockedCompareExchange128 โ€“ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ์„ค์ • ๋ถˆ๊ฐ€
  • 44.
    Lock Free Queue๊ตฌํ˜„
  • 45.
    Queue โ€ข ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ์‚ฌ์šฉํ•œ ๊ตฌํ˜„ ๊ฐœ๋… ์ดํ•ด๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ (์›๋ž˜๋Š” shared_ptr๋ฅผ ์”๋‹ˆ๋‹ค)
  • 46.
    Queue โ€ข ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ์‚ฌ์šฉํ•œ ๊ตฌํ˜„ DC Tail B Head A pop push
  • 47.
    Queue ์˜ ๊ตฌ๋ถ„ โ€ขSingle-producer (SP) โ€ข Multi-producer (MP) โ€ข Single-consumer (SC) โ€ข Multi-consumer (MC) โ€ข ์ œ์•ฝ ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ โ€“ SPSC, SPMC, MPSC, MPMC ๋กœ ๊ตฌ๋ถ„ ์ด๊ฑด ์‰ฌ์›€
  • 48.
    Queue โ€ข Thread๋ฅผ ๊ณ ๋ คํ•˜์ง€์•Š์€ ๋‹จ์ˆœ ๊ตฌํ˜„ ๋น„์–ด ์žˆ์„ ๋•Œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•˜๋‚˜ ์žˆ์„ ๋•Œ๋„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
  • 49.
    ์ด๋ฏธ ๋ญ”๊ฐ€ ๋ณต์žกํ•˜๋‹ค? ์ด๋ฐฉ์‹์„ lock-free๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ๋Š” ํž˜๋“ฆ..
  • 50.
    ๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”Queue โ€“ Head์™€ Tail์€ ํ•ญ์ƒ null์ด ์•„๋‹˜ โ€“ pop(), push() ๊ตฌํ˜„์ด ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅ /C Tail B Head A
  • 51.
    ๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”Queue โ€ข push() โ€“ ๋”๋ฏธ ๋…ธ๋“œ์— ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ ๏ƒ  ์‹ค์ œ node๊ฐ€ ๋จ โ€“ ์ดํ›„ ์ƒˆ๋กœ์šด ๋”๋ฏธ ๋…ธ๋“œ ์ƒ์„ฑ ๏ƒ  Head๋ฅผ ์ˆ˜์ • ํ•  ํ•„์š”๊ฐ€ ์—†์Œ /C Tail B Head A
  • 52.
    ๋”๋ฏธ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”Queue โ€ข pop() โ€“ Head != Tail ์ธ ๊ฒฝ์šฐ์—๋งŒ pop() โ€“ Tail์„ ์ˆ˜์ • ํ•  ํ•„์š”๊ฐ€ ์—†์Œ /C Tail B Head A
  • 53.
    SPSC Lock-free Queue โ€ขPush ๊ตฌํ˜„ โ€“ tail ํฌ์ธํ„ฐ๋ฅผ atomic ์œผ๋กœ ๊ตฌํ˜„ โ€“ (1)์—์„œ ๋”๋ฏธ ๋…ธ๋“œ์— ๋ฐ์ดํ„ฐ ๋„ฃ์Œ (1) (2)
  • 54.
    SPSC Lock-free Queue โ€ขPop ๊ตฌํ˜„ โ€“ (3) ์ด (2)์™€ synchronized-with ๊ด€๊ณ„ โ€“ ์—ฌ๊ธฐ๊นŒ์ง€๋Š” SPSC์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ๋™์ž‘ (3)
  • 55.
    Multi-consumer pop() โ€ข Head!= Tail ์ฒดํฌ ํ›„ CAS๋กœ pop ์‹œ๋„ ๋ฐ˜๋ณต โ€ข ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ โ€“ ์Šคํƒ ๊ตฌํ˜„์—์„œ ์ด๋ฏธ ๋‹ค๋ฃฌ ๋ฌธ์ œ (์ฑ…์—์„œ๋Š” ์Šคํƒ์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ Split Reference Count๋กœ ์ง„ํ–‰)
  • 56.
    Multi-producer push() / Tail B Head A C /C Tail B Head A 1) CAS๋กœ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ 2) ์ƒˆ ๋…ธ๋“œ ์ถ”๊ฐ€ 3) Tail ๋ณ€๊ฒฝ
  • 57.
    ๋ฌธ์ œ์  #1 :CAS ์‹œ์ ์˜ tail โ€ข CAS ์‹œ์ ์— Tail์ด ํ•ด์ œ ๋˜์—ˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด ์‹œ์ ์—์„œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ Push ๏ƒ  Pop ์ผ์–ด๋‚˜๋ฉด old_tail ์‚ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ
  • 58.
    Split Reference Count โ€ขtail ๋„ counted_node_ptr๋กœ ๊ตฌํ˜„ โ€ข counted_node_ptr์˜ ๊ฐœ์ˆ˜๋ฅผ ์ฒดํฌ /C Tail B Head A
  • 59.
    Split Reference Count โ€ขexternal count โ€“ ์ตœ๋Œ€ 2๊ฐœ โ€ข internal count โ€ข external_counters counted_node_ptr external_count ptr counted_node_ptr external_count ptr node data internal_count counted_node_ptr ext_counters = 2
  • 60.
    ๋ฌธ์ œ์  #2 :Blocking โ€ข Push ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„... โ€“ ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ ํ•œ ์ƒํƒœ์—์„œ, โ€“ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„๋งŒ ๋ฐ˜๋ณตํ•˜๋ฉด? โ€ข ๊ณ„์† ์‹คํŒจ, lock-free๊ฐ€ ์•„๋‹ˆ๊ฒŒ ๋จ DC Tail B Head A
  • 61.
    Blocking ๋ฌธ์ œ ํ•ด๊ฒฐ โ€ขTail node์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€ ๋˜์—ˆ์„ ๋•Œ โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒˆ dummy node ์ถ”๊ฐ€ ์‹œ๋„ โ€“ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒˆ ๋…ธ๋“œ๋กœ Tail ๋ณ€๊ฒฝ ์‹œ๋„ ์ฑ…์„ ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. (์–ด๋ ค์šฐ๋‹ˆ ๊ฐ์˜คํ•˜์‹œ๊ณ ..)
  • 62.
    Lock Free Queue์ •๋ฆฌ โ€ข CAS๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ โ€ข ์–ด๋ ค์šด ๋ถ€๋ถ„ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๋ฌธ์ œ โ€“ ์Šคํƒ๊ณผ ๊ทผ๋ณธ์ ์œผ๋กœ๋Š” ๊ฐ™์€ ๋ฌธ์ œ โ€“ Tail ์ฒ˜๋ฆฌ ๊ตฌํ˜„ ์ค‘ ์ถ”๊ฐ€๋กœ ํŒŒ์ƒ๋˜๋Š” ๋ฌธ์ œ โ€ข ABA ๋ฌธ์ œ โ€ข Blocking ( busy-waiting ) ๋ฌธ์ œ
  • 63.
    ์ด์ •๋ฆฌ โ€ข Lock-free ์ž๋ฃŒ๊ตฌ์กฐ์ž‘์„ฑ ์š”๋ น โ€“ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ์„ ๊ณ ๋ คํ•˜์ง€๋Š” ์•Š์Œ โ€ข ์ด๋ฏธ ์ถฉ๋ถ„ํžˆ ์–ด๋ ค์šฐ๋‹ˆ๊นŒ โ€“ Lock-free ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ๊ธฐ๋ฒ•๋“ค ์ ์šฉ โ€ข stack ๊ตฌํ˜„์—์„œ ์ œ์‹œํ•œ ์„ธ ๊ฐ€์ง€ ๊ธฐ๋ฒ• โ€“ ABA ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ณ ๋ ค ํ•„์š” โ€“ Busy-waiting์„ ์ธ์ง€ํ•˜๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ ์ผ ํ•ด์ฃผ๊ธฐ โ€ข ๋ˆ„๊ฐ€ ์‹œ์ž‘ํ–ˆ๋˜ ๋ฉˆ์ถ”๋ฉด ์•ˆ๋จ
  • 64.
    ๊ฒฐ๋ก  โ€ข ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ๋Š”์–ด๋ ต๋‹ค โ€ข ๋Œ€์•ˆ โ€“ ์ž˜ ๊ตฌํ˜„๋œ ๊ตฌํ˜„์ฒด ( boost, intel TBB ๋“ฑ ) ์‚ฌ์šฉ โ€“ MPSC ํ˜•ํƒœ ์ฒ˜๋Ÿผ ์ œ์•ฝ์„ ์ฃผ๋Š” ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ โ€“ Java๋‚˜ C# ์‚ฌ์šฉ...