[Concurrency] Test And Set (TAS)
Test And Set(์ดํ TAS)๋ ๋์์ฑ ํ๊ฒฝ์์์ ๋๊ธฐํ๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ๊ธฐ๋ฒ ์ค ํ๋๋ค.
Compare And Swap์ด Lock-free๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ์ฐ์ฐ ๋จ์๋ก ์์ฉ๋๋ค๋ฉด, TAS๋ Spin-Lock์ ๊ตฌํํ๋๋ฐ ์ฃผ๋ก ์ฌ์ฉ๋๋ค. Mutex ๊ฐ์ lock ๊ธฐ๋ฐ์ ๋๊ธฐํ ๋งค์ปค๋์ฆ์ ๋ณดํต ์ด๋ฐ๊ฑธ ํตํด ๊ตฌํ๋๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
์๋๋ TAS์ ์๋ฆฌ๋ฅผ ๋ํ๋ด๋ C ์ฝ๋๋ค.
// lock์ ํ๋ํ์ง ๋ชปํ์ผ๋ฉด true ๋ฐํ
// lock์ ํ๋ํ๋ค๋ฉด true๋ก ์ค์ ํ๊ณ false ๋ฐํ
bool test_and_set(bool* locked) {
if(*locked) {
return true;
} else {
*locked = true;
return false;
}
}
์ด๋ฏธ lock์ ์ ์ ํ๊ณ ์๋ค๋ฉด true๋ฅผ ๋ฐํํ๊ณ , ์๋๋ผ๋ฉด false๋ฅผ ๋ฐํํ๋ค.
์ด๊ฑธ ์์ฉํ๋ฉด ๋ฐ๋ก Spin-Lock์ ํตํด ๋๊ธฐํ๋ฅผ ๊ตฌํํ ์ ์๋ค.
์๋๋ ๋ฐฉ๊ธ ์์ฑํ test_and_set์ ์ด์ฉํ spin-lock์ ๊ตฌํ๋ก๋ค.
...
bool lock = false; // lock์ฉ ๊ณต์ ๋ณ์
...
// A thread
void spawn_thread(bool* lock) {
// lock์ ์ ์ ํ ๋๊น์ง ๋ฌดํ๋ฃจํ๋ก ๋๊ธฐ (Spin-Lock)
while(!test_and_set(lock));
// ์ ์ ํ์ ๊ฒฝ์ฐ ์ง์
...์์
// lock ํด์
*lock = false;
}
๋ค๋ง ์ด ์ฝ๋๋ ๊ฐ๋ ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์์ฑํ ๊ฒ์ด๋ผ ์ค์ ๋ก atomicํ๊ฒ ๋์ํ์ง๋ ์๋๋ค.
๋์ gcc๋ clang์์๋ atomicํ TAS ํจ์๋ก __sync_lock_test_and_set์ด๋ผ๋ ํจ์๋ฅผ ์ ๊ณตํ๋ค.
์ ๋ฐ๊ฑธ ์ฐ๋ฉด ๋๋ค.
์ด์ ๋ธ๋ฆฌ ์์ค (x86-64)
C์์ ํน์ํ ํจ์์ ํํ๋ก๋ง ๊ตฌํ์ด ๊ฐ๋ฅํ ๊ฒ์ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, ์ด๊ฑด CPU์ ๋ช
๋ น์ ์์กด์ ์ธ ๊ธฐ๋ฅ์ด๋ค.
x86 ํ๋ก์ธ์์์ TAS๋ "xchgb"์ ๊ฐ์ ๋ช
๋ น์ ํตํด ์ ๊ณต๋๋ค.
movb $1, %al
xchgb %al, (%rdi) ; TAS
...ํจ์จ์ฑ?
์ฌ์ค TAS ๊ธฐ๋ฐ์ ์คํ๋ฝ์ ํจ์จ์ฑ์ด ๋ฑํ ์ข์ํธ์ด ์๋๋ค.
์ผ๋ฐ์ ์ธ ์ํํธ์จ์ด ์์ค์์๋ Mutex ๊ฐ์ ๊ธฐ๋ณธ ๋ฝ์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋๋ฆฌ๊ณ ๋นํจ์จ์ ์ด๋ค.
์คํ๋ฝ์ด ์ข์ ์ฑ๋ฅ์ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ ๋งค์ฐ ๊ทน๋จ์ ์ธ ์ํฉ ๋ฟ์ด๋, ์ผ๋ฐ์ ์ผ๋ก๋ ์ฐ์ง ์๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
์ค๋ ๋์ ์๊ฐ ๋ฌผ๋ฆฌ ์ฝ์ด์ ์๋ฅผ ๋์ง ์๊ณ , ํ ๋น์ด ๋ง์ง ์์ ๊ฒฝ์ฐ์๋ ์คํ๋ฝ์ด ์ข์ ์ ์๋ค๊ณ ํ๋ค.
์ฐธ์กฐ
https://en.wikipedia.org/wiki/Test-and-set
https://stackoverflow.com/questions/3659336/compare-and-swap-vs-test-and-set
https://mmomtchev.medium.com/spinlock-vs-mutex-performance-3f73de53a460