Post

[OS] Operating System(4-2): Thread Pool

[OS] Operating System(4-2): Thread Pool

๐Ÿ€ ์šด์˜์ฒด์ œ ์ „๊ณต ์ˆ˜์—… ์ •๋ฆฌ

Implicit Threading


์ตœ๊ทผ ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ํ”„๋กœ๊ทธ๋žจ์˜ ์ •ํ™•์„ฑ ๋ณด์žฅ์ด ์–ด๋ ค์›Œ์ง ์ด๋Ÿฐ ๋ณต์žก์„ฑ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด complier์™€ run-time library๊ฐ€ ์Šค๋ ˆ๋“œ์˜ ์ƒ์„ฑ๊ณผ ๊ด€๋ฆฌ๋ฅผ ๋‹ด๋‹น

  • ๊ฐœ๋ฐœ์ž๋Š” ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” task๋ฅผ ์ง€์ •๋งŒ ํ•˜๋ฉด ๋จ

  • Thread Pools: ์“ฐ๋ ˆ๋“œ์˜ ์ˆ˜๋ฅผ ์กฐ์ ˆํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋‘๊ณ  ์ž‘์—…์„ ํ• ๋‹น
  • Fork-Join: ์ž‘์—…์„ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋‚˜๋ˆ„๊ณ  (fork), ๋‹ค ๋๋‚˜๋ฉด ๋‹ค์‹œ ํ•ฉ์นจ (join)
  • OpenMP: C/C++์—์„œ #pragma๋กœ ๋ณ‘๋ ฌ ์ฝ”๋“œ ์‰ฝ๊ฒŒ ์ž‘์„ฑ
  • Grand entral Dispatch: ์• ํ”Œ์—์„œ ๋งŒ๋“  ์Šค๋ ˆ๋“œ ํ’€ ๊ธฐ๋ฐ˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ํ”„๋ ˆ์ž„์›Œํฌ
  • Intel Threading Building Blocks: C++ ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Thread Pools


๐Ÿ“šThread Pools: ๋ฏธ๋ฆฌ ์ƒ์„ฑ๋œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ thread๋ฅผ pool์ด๋ผ๋Š” ๊ณต๊ฐ„์— ๋Œ€๊ธฐ์‹œ์ผœ ๋†“๊ณ , ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ์ด pool์—์„œ thread๋ฅผ ๊ฐ€์ ธ์™€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹

โœ…Thread Pools์˜ ์žฅ์ 

  1. ์†๋„ ํ–ฅ์ƒ: ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ฝ๊ฐ„ ๋” ๋น ์œผ
  2. ์Šค๋ ˆ๋“œ ์ˆ˜ ์ œํ•œ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” thread์˜ ์ˆ˜๋ฅผ pool ํฌ๊ธฐ๋กœ ์ œํ•œ ๊ฐ€๋Šฅ โ†’ ์‹œ์Šคํ…œ ์ž์›์˜ ๊ณผ๋„ํ•œ ์‚ฌ์šฉ์„ ๋ฐฉ์ง€
  3. ์ž‘์—…๊ณผ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋ถ„๋ฆฌ: task๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๋ถ„๋ฆฌํ•จ โ†’ ๋‹ค์–‘ํ•œ ์ „๋žต์œผ๋กœ ์ž‘์—…์„ ์‹คํ–‰ ๊ฐ€๋Šฅ
    • ์˜ˆ: ์ž‘์—…์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ์Šค์ผ€์ค„๋ง
  • Windows API์—์„œ์˜ ์Šค๋ ˆ๋“œ ํ’€ ์ง€์› ```c DWORD WINAPI PoolFunction(AVOID Param) { /*
    • this function runs as a separate thread. */ } ```

QueueUserWorkItem() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด pool์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ PoolFunction์„ ์‹คํ–‰ํ•˜๊ฒŒ ํ•จ

  • Thread Pools์˜ ์ž‘๋™๋ฐฉ์‹:
    1. ํ’€์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋“ค์€ ์ž‘์—…์ด ํ• ๋‹น๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ
    2. ์ž‘์—…์ด ์š”์ฒญ๋˜๋ฉด ํ’€์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•ด๋‹น ์ž‘์—…์„ ์ˆ˜ํ–‰
    3. ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์Šค๋ ˆ๋“œ๋Š” ๋‹ค์‹œ ํ’€๋กœ ๋Œ์•„๊ฐ€์„œ ๋‹ค์Œ ์ž‘์—…์„ ๋Œ€๊ธฐ

alt text

โŒThread pool์˜ Sleeping Barber Problem:

  1. ์ด๋ฐœ์‚ฌ(์Šค๋ ˆ๋“œ)๊ฐ€ ๊ณ ๊ฐ์ด ์—†์„ ๋•Œ๋Š” ์ž ์„ ์ž๊ณ (๋Œ€๊ธฐ ์ƒํƒœ), ๊ณ ๊ฐ์ด ์˜ค๋ฉด ๊นจ์–ด๋‚˜ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณต
  2. ๋Œ€๊ธฐ์‹ค์— ์ œํ•œ๋œ ์ˆ˜์˜ ์˜์ž(ํ’€ ํฌ๊ธฐ)๊ฐ€ ์žˆ์–ด, ๊ณ ๊ฐ(์ž‘์—…)์ด ๋” ์ด์ƒ ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†์œผ๋ฉด ๋– ๋‚œ๋‹ค
  3. ์Šค๋ ˆ๋“œ ํ’€ ์—ญ์‹œ ์ด์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ œํ•œ๋œ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ๊ธฐ๋‹ค๋ฆฌ๋‹ค๊ฐ€ ์ž‘์—…์ด ๋“ค์–ด์˜ค๋ฉด ์ฒ˜๋ฆฌ

Fork-join


๐Ÿ“š Fork-Join Parallelism: ํ•˜๋‚˜์˜ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ **์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—… ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑ**(`fork`), ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์‹œ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋กœ ํ•ฉ์น˜๋Š”(join) ๋ฐฉ์‹

alt text

Multiple threads (tasks) are forked, and then joined

  • ์ž‘๋™ ๋ฐฉ์‹:
    1. Fork: ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—… ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑ
    2. ๋ณ‘๋ ฌ ์‹คํ–‰: ์ƒ์„ฑ๋œ ์ž‘์—… ์Šค๋ ˆ๋“œ๋“ค์ด ๋™์‹œ์—(๋ณ‘๋ ฌ๋กœ) ์‹คํ–‰
    3. Join: ๋ชจ๋“  ์ž‘์—… ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋กœ ๋‹ค์‹œ ๋ณ‘ํ•ฉ

Fork-Join์€ ์žฌ๊ท€์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค!

alt text

merge_sort์˜ ๊ณผ์ •๊ณผ ํก์‚ฌํ•จ

  • ํ•˜๋‚˜์˜ ์ž‘์—…์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์„œ๋ธŒ์ž‘์—…์„ ํฌํฌ ๊ฐ€๋Šฅ
  • ๊ฐ ์„œ๋ธŒ์ž‘์—…์€ ๋˜ ๋‹ค๋ฅธ ์„œ๋ธŒ์ž‘์—…๋“ค์„ ํฌํฌ ๊ฐ€๋Šฅ
  • ๋ชจ๋“  ์„œ๋ธŒ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ƒ์œ„ ์ž‘์—…์œผ๋กœ ์กฐ์ธ

OpenMP


OpenMP: ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ณ‘๋ ฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ API OpenMP๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ์ง€์‹œ๋ฌธ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.

#pragma omp parallel์„ ์“ฐ๊ณ  ์ค‘๊ด„ํ˜ธ ์‚ฌ์ด์˜ ์ฝ”๋“œ๋ฅผ ์ฝ”์–ด์˜ ์ˆ˜๋งŒํผ ์ค‘๋ณตํ•ด์„œ ์‹คํ–‰ํ•œ ๋’ค ์ข…๋ฃŒํ•˜๊ณ  join์„ ํ•จ

1
2
3
4
#pragma omp parallel
    {
        printf("[T%d] Hello, world!\n", id);
    }

for loop ์ƒํ™ฉ๋„ ๊ฐ€๋Šฅํ•จ

1
2
3
4
5
6
// ์ฝ”์–ด์˜ ์ˆ˜๋งŒํผ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  N๊ฐœ์˜ iteration์„ ์Šค๋ ˆ๋“œ์— ๋ถ„ํ• ๋งคํ•‘
// ๋งŒ์•ฝ ์ฝ”์–ด์˜ ์ˆ˜๊ฐ€ 10๊ฐœ๋ฉด 3,3,2,2 ์‹์œผ๋กœ ๋งคํ•‘ํ•œ๋‹ค
#pragma omp parallel for
for (i=0; i<N; i++){
  c[i] = a[i] + b[i]
}

์ด ์˜ˆ์ œ์—์„œ๋Š” data์˜ ์ข…์†์„ฑ์ด ์—†์–ด์„œ ๋ณ‘๋ ฌ ์‹คํ–‰์ด ๊ฐ€๋Šฅ ์ข…์†์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ฃผ์˜ํ•ด์•ผ ํ•จ ์Šค๋ ˆ๋“œ์˜ ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ num_threads(N) ๋งคํ•‘ ์ˆœ์„œ์— ๋ณ€ํ™”๋ฅผ ์ค„ ์ˆ˜ ์žˆ์Œ schedule(dynamic)

Grand Central Dispatch(GCD)


Apple์ด ๊ฐœ๋ฐœํ•œ thread pool, macOS/iOS์—์„œ ์‚ฌ์šฉ๋จ

  • task๋ฅผ queue์— ์ œ์ถœํ•˜๋ฉด ์‹œ์Šคํ…œ์ด ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ์™€ ์Šค์ผ€์ค„๋ง์„ ๋‹ด๋‹น

โœ…์ฃผ์š” ํŠน์ง•:

  • ํ™•์žฅ์„ฑ: C, C++, Objective-C ์–ธ์–ด, API ๋ฐ ๋Ÿฐํƒ€์ž„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํ™•์žฅ
  • ๋ณ‘๋ ฌ ์„น์…˜ ์‹๋ณ„: ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ์˜ ์–ด๋А ๋ถ€๋ถ„์„ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์Šค๋ ˆ๋”ฉ ์„ธ๋ถ€์‚ฌํ•ญ ๊ด€๋ฆฌ: GCD๋Š” ์Šค๋ ˆ๋”ฉ์˜ ๋Œ€๋ถ€๋ถ„์˜ ์„ธ๋ถ€์‚ฌํ•ญ์„ ๊ด€๋ฆฌํ•ด์ฃผ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ €์ˆ˜์ค€ ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.

  • ์ž‘๋™ ๋ฐฉ์‹:
    1. Block ์ •์˜: ์ž‘์—…์„ ๋ธ”๋ก์œผ๋กœ ์ •์˜
1
^{ printf("I am a block"); }
  1. ์ •์˜๋œ ๋ธ”๋ก์„ Dispatch Queue์— ๋ฐฐ์น˜
  2. ๋ธ”๋ก์ด ํ์—์„œ ์ œ๊ฑฐ๋  ๋•Œ ์Šค๋ ˆ๋“œ ํ’€์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ์— ํ• ๋‹น๋จ

โœ… Dispatch์˜ ๋‘ ๊ฐ€์ง€ ์œ ํ˜•

  1. Serial Queue:
    • ๋ธ”๋ก์ด FIFO ์ˆœ์„œ๋กœ ํ•˜๋‚˜์”ฉ ์ œ๊ฑฐ๋จ
    • ๊ฐ ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ํ•˜๋‚˜์˜ ๋ฉ”์ธ ํ(main queue)๊ฐ€ ์žˆ์Œ
  2. Concurrent Queue:
    • ๊ฐ ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ํ•˜๋‚˜์˜ main queue๊ฐ€ ์žˆ์Œ
    • ์„œ๋น„์Šค ํ’ˆ์งˆ(QoS)์— ๋”ฐ๋ผ ๊ตฌ๋ถ„๋œ 4๊ฐ€์ง€ ์‹œ์Šคํ…œ ์ „์—ญ ํ:
    • QOS_CLASS_USER_INTERACTIVE: ์‹ ์†ํ•œ ์‘๋‹ต์ด ์š”๊ตฌ๋  ๋•Œ (UI ๊ด€๋ จ)
    • QOS_CLASS_USER_INITIATED: ์ ๋‹นํ•œ ์‹œ๊ฐ„์˜ ์‘๋‹ต์ด ์š”๊ตฌ๋  ๋•Œ
    • QOS_CLASS_USER_UTILITY: ๊ธด ์‹œ๊ฐ„์ด ์š”๊ตฌ๋  ๋•Œ
    • QOS_CLASS_USER_BACKGROUND: ์‹œ๊ฐ„์— ๊ด€๊ณ„์—†๋Š” ์ž‘์—…์ผ ๋•Œ

Intel Threading Building Blocks (TBB)


๐Ÿ“šIntel TBB: Template library for designing parallel C++ programs

TBB๋Š” ๊ธฐ์กด ์ˆœ์ฐจ์  ์ฝ”๋“œ๋ฅผ ๋ณ‘๋ ฌ ์ฝ”๋“œ๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค:

  • ์ˆœ์ฐจ์  for ๋ฃจํ”„:
1
2
3
for (int i = 0; i < n; i++) {
    apply(v[i]);
}
  • TBB๋ฅผ ์ด์šฉํ•œ ๋ณ‘๋ ฌ for ๋ฃจํ”„:
    1
    
    parallel_for (size_t(0), n, [=](size_t i) {apply(v[i]);});
    

Threading Issues


  1. Semantics of fork() and exec() system calls
  2. Signal handling
    • Synchronous(๋‚ด๋ถ€์—์„œ๋ฐœ์ƒ) and asynchronous(์™ธ๋ถ€์—์„œ๋ฐœ์ƒ)
  3. Thread cancellation of target thread
    • Asynchronous(์™ธ๋ถ€์— ์˜ํ•ด ์บ”์Šฌ) or deferred(์Šค๋ฌด์Šคํ•˜๊ฒŒ ์บ”์Šฌ)
  4. Thread-local storage

Semantics of fork() and exec() system calls


ํ•œ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ชจ๋‘ fork()ํ•ด์•ผํ•˜๋Š”๊ฐ€? โ†’ ๋Œ€๋ถ€๋ถ„ main thread ํ•œ ๊ฐœ๋งŒ fork()ํ•จ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋‹ค ๋ณต์ œํ–ˆ๋”๋‹ˆ ๋ฎ์–ด์”Œ์šฐ๋ฉด ๋‚ญ๋น„์ด๋‹ˆ fork() ํ›„ exec() ๋ฐฉ์‹์„ ์‚ฌ์šฉ

โŒโ€Dont use both threads and forksโ€

Signal handling


๐Ÿ“š Signal: โ€œํ”„๋กœ์„ธ์Šคโ€์—๊ฒŒ ์‹ ํ˜ธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ํ–‰์œ„, ์Šค๋ ˆ๋“œํ•œํ…Œ๋„ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Œ

  • ๋ฐœ์ƒ ์›์ธ:
    • ๋‚ด๋ถ€ ๋ฐœ์ƒ: ๋ถˆ๋ฒ• ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ, 0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ ๋“ฑ
    • ์™ธ๋ถ€ ๋ฐœ์ƒ: Ctrl+C, ํƒ€์ด๋จธ ๋“ฑ
  • ์–ด๋–ค ์‹œ๊ทธ๋„์„ ํŠน์ • ์Šค๋ ˆ๋“œ์—๊ฒŒ ๋ณด๋ƒˆ๋Š”๋ฐ ํŠน์ • ์ฒ˜๋ฆฌ๋ฅผ ์•ˆํ•˜๋ฉด ๊ทธ ์Šค๋ ˆ๋“œ๋งŒ ์ฃฝ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ํ”„๋กœ์„ธ์Šค ์ „์ฒด๊ฐ€ ๋‹ค ์ฃฝ์Œ

โœ…์‹œ๊ทธ๋„ ์ฒ˜๋ฆฌ ๋ฐฉ์‹:

  1. ์‹œ๊ทธ๋„์€ ํŠน์ • ์ด๋ฒคํŠธ์— ์˜ํ•ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ(์˜ˆ:ctrl+c)
  2. ํ”„๋กœ์„ธ์Šค์— ์ „๋‹ฌ๋จ(์Šค๋ ˆ๋“œ์—๊ฒŒ๋งŒ๋„ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์œ„ํ—˜ํ•จ. ๊ทธ๋ž˜์„œ ํ”„๋กœ์„ธ์Šค์˜ ์ „์ฒด ์Šค๋ ˆ๋“œ์—๊ฒŒ ์ „๋‹ฌ)
  3. ์‹œ๊ทธ๋„์€ ๋‘๊ฐœ ์ค‘ ํ•˜๋‚˜
    1. ๊ธฐ๋ณธ ํ•ธ๋“ค๋Ÿฌ(default): ์ปค๋„์ด ์‹œ๊ทธ๋„ ์ฒ˜๋ฆฌ ์‹œ ์‹คํ–‰
    2. ์‚ฌ์šฉ์ž ์ •์˜ ํ•ธ๋“ค๋Ÿฌ(user-defined): ๊ธฐ๋ณธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ

์‹œ๊ทธ๋„์˜ ๊ธฐ๋ณธ ํ–‰์œ„๋Š” ์ฃฝ๋Š”๊ฑด๋ฐ(์ปค๋„ ์ฒ˜๋ฆฌ), ์‚ฌ์šฉ์ž๊ฐ€ ์ฃฝ๋Š”๊ฒŒ ์‹ซ์œผ๋ฉด ์˜ค๋ฒ„๋ผ์ด๋“œ ๊ฐ€๋Šฅ

  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‹œ๊ทธ๋„์„ ์–ด๋–ค ์Šค๋ ˆ๋“œ๋กœ ์ „๋‹ฌํ• ์ง€๋Š” ์ค‘์š”ํ•œ ๋ฌธ์ œ!
    • ์ ์šฉ๋˜๋Š” ์Šค๋ ˆ๋“œ์—๋งŒ ์ „๋‹ฌ: divide by zero ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ
    • ๋ชจ๋“  ์Šค๋ ˆ๋“œ์— ์ „๋‹ฌ: (์˜ˆ: ctrl+c)/ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„ ์ค‘๋ณต๋œ ์‹œ๊ทธ๋„์€ ์ฒซ๋ฒˆ์งธ ๊ฒƒ๋งŒ ์ˆ˜์šฉํ•˜๊ณ  ๋‚˜๋จธ์ง„ ๋ฌด์‹œ
    • ํŠน์ •ํ•œ ์Šค๋ ˆ๋“œ์—๋งŒ ์ „๋‹ฌ
    • ํŠน์ • ์Šค๋ ˆ๋“œ๊ฐ€ ๋ชจ๋“  ์‹œ๊ทธ๋„ ์ฒ˜๋ฆฌ: ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ชจ๋“  ์‹œ๊ทธ๋„์„ ๋ฐ›๋„๋ก ์ง€์ •

signal์€ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‘ ๊ฐ€์ง€๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค:

  1. Synchronous ์‹œ๊ทธ๋„: ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ ์ฝ”๋“œ์— ์˜ํ•ด ์ง์ ‘ ๋ฐœ์ƒํ•˜๋Š” ์‹œ๊ทธ๋„(์˜ˆ: ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜, 0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ)
  2. Asynchronous ์‹œ๊ทธ๋„: ํ”„๋กœ๊ทธ๋žจ ์™ธ๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์‹œ๊ทธ๋„(์˜ˆ: Ctrl+C, ํƒ€์ด๋จธ)
1
2
kill(pid_t pid, int signal); // ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฃฝ์ด๋Š” ํ•จ์ˆ˜
pthread_kill(pthread_t tid, int signal)// ์Šค๋ ˆ๋“œ๋ฅผ ์ฃฝ์ด๋Š” ํ•จ์ˆ˜
  • ๋Œ€๋ถ€๋ถ„์˜ Unix๊ณ„์—ด์˜ OS์—์„œ๋Š” ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋ฐ›๋Š” ๋˜๋Š” ๊ฑฐ๋ถ€ํ•˜๋Š” signal์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ.
  • ๋”ฐ๋ผ์„œ ๋‹ค์ค‘์Šค๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ signal์„ ํ—ˆ์šฉํ•˜๋Š” ์ฒซ๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ฒ˜๋ฆฌํ•จ

Thread cancellation of target thread


์Šค๋ ˆ๋“œ๊ฐ€ ๋๋‚˜๊ธฐ ์ „์— ์ข…๋ฃŒํ•˜๋Š” ํ–‰์œ„

  • Target thread: ์ทจ์†Œ๋  ์Šค๋ ˆ๋“œ
  • ์ทจ์†Œ ๋ฐฉ์‹:
    1. ๋น„๋™๊ธฐ์‹ ์ทจ์†Œ(Asynchronous Cancellation): ์ฆ‰๊ฐ์ ์œผ๋กœ ํƒ€๊ฒŸ ์Šค๋ ˆ๋“œ๋ฅผ ์ข…๋ฃŒ โ†’ ํ• ๋‹น๋œ ์ž์›์„ ๋ชจ๋‘ freeํ•˜์ง€ ๋ชปํ•  ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ
    2. ์ง€์—ฐ ์ทจ์†Œ(Deferred Cancellation): ์ข…๋ฃŒํ•  ํƒ€๊ฒŸ ์Šค๋ ˆ๋“œ๋ฅผ periodcally checkํ•˜๊ณ  ์žˆ์Œ
      • Cancellation point์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์บ”์Šฌํ•จ.
      • ์ผ๋ฐ˜์ ์œผ๋กœ read()์™€ ๊ฐ™์€ blocking system call์ด cancellation point๊ฐ€ ๋จ
1
2
3
4
5
6
7
8
9
10
pthread_t tid;

/* ์Šค๋ ˆ๋“œ ์ƒ์„ฑ */
pthread_create(&tid, 0, worker, NULL);

/* ์Šค๋ ˆ๋“œ ์ทจ์†Œ */
pthread_cancel(tid);

/* ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ ๋Œ€๊ธฐ */
pthread_join(tid, NULL);

์Šค๋ ˆ๋“œ ์ทจ์†Œ ์š”์ฒญ์„ ๋ณด๋‚ด๋„ ์‹ค์ œ ์ทจ์†Œ๋Š” ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ฆฌ์ง„๋‹ค:

alt text

์Šค๋ ˆ๋“œ๊ฐ€ ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ๋น„ํ™œ์„ฑํ™”ํ•œ ๊ฒฝ์šฐ, ์ทจ์†Œ ์š”์ฒญ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ํ™œ์„ฑํ™”ํ•  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ์œ ์ง€
๊ธฐ๋ณธ ์ทจ์†Œ ์œ ํ˜•์€ ์ง€์—ฐ ์ทจ์†Œ(Deferred)

  • ์ง€์—ฐ ์ทจ์†Œ(Deferred Cancellation)์—์„œ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ โ€œ์ทจ์†Œ ์ง€์ โ€œ์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ๋งŒ ์ทจ์†Œ๋œ๋‹ค
    • pthread_testcancel() ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ
    • read()์™€ ๊ฐ™์€ ๋ธ”๋กœํ‚น ์‹œ์Šคํ…œ ์ฝœ์ด ์ทจ์†Œ ์ง€์ ์ด ๋  ์ˆ˜ ์žˆ์Œ ์ทจ์†Œ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ์ •๋ฆฌ ํ•ธ๋“ค๋Ÿฌ(cleanup handler)๊ฐ€ ํ˜ธ์ถœ๋จ

๋งŒ์•ฝ ์บ”์Šฌํ•  ์Šค๋ ˆ๋“œ๊ฐ€ cancellation point๋กœ ์•ˆ๊ฐ€๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€?

โ†’ ์ทจ์†Œ ํ”Œ๋ž˜๊ทธ๋Š” ์„ค์ •๋˜์ง€๋งŒ ์‹ค์ œ ์ทจ์†Œ๋Š” ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, ์Šค๋ ˆ๋“œ๊ฐ€ ํ™œ์„ฑํ™” ๋ ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ

Thread-local storage(TLS)


์Šค๋ ˆ๋“œ๋Š” ์ž์›์„ ๊ณต์œ ํ•˜์ง€๋งŒ(์ „์—ญ๋ณ€์ˆ˜: ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  ์Šค๋ ˆ๋“œ์— ์ ์šฉ) โ†’ ์ง€์—ญ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•  ๊ฒฝ์šฐ๋„ ์žˆ์Œ(thread pool์˜ ๊ฒฝ์šฐ์— ํ•„์š”ํ•จ) โ†’ ์Šค๋ ˆ๋“œ pool์„ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๋Š” ์Šค๋ ˆ๋“œ ์ƒ์„ฑ์— ๊ด€์—ฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— TLS๊ฐ€ ์œ ์šฉ

๐Ÿ“šTLS(Thread-local storage): ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณ ์œ ํ•œ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์ €์žฅ ๊ณต๊ฐ„

์ง€์—ญ ๋ณ€์ˆ˜์™€ TLS ๋ณ€์ˆ˜๋Š” ๋‹ค๋ฆ„!

  • ์ง€์—ญ ๋ณ€์ˆ˜(Local Variables): ๋‹จ์ผ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
  • TLS ๋ณ€์ˆ˜: ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฐ„์—๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํ•ด๋‹น ์Šค๋ ˆ๋“œ ๋‚ด์—์„œ๋งŒ ์œ ํšจ
  • static data์™€ ํก์‚ฌํ•จ
    • TLS๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—๊ฒŒ uniqueํ•จ

Linux Threads


linux๋Š” ์Šค๋ ˆ๋“œ ๋ณด๋‹ค task๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์„ ์„ ํ˜ธ

  • task ์ƒ์„ฑ์€ clone() ์‹œ์Šคํ…œ ์ฝœ์„ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง„๋‹ค
  • clone(): ์ž์‹ ํƒœ์Šคํฌ(์Šค๋ ˆ๋“œ)๊ฐ€ ๋ถ€๋ชจ ํƒœ์Šคํฌ(ํ”„๋กœ์„ธ์Šค)์˜ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ

clone() ํ•จ์ˆ˜์˜ ๋™์ž‘์€ ๋‹ค์–‘ํ•œ ํ”Œ๋ž˜๊ทธ๋กœ ์ œ์–ด ๊ฐ€๋Šฅ alt text

fork()์™€ clone()์˜ ์ฐจ์ด์ :

  • fork(): ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋ณต์‚ฌ(๋ณต์‚ฌ๋ณธ ์ฒ˜๋ฆฌ)
  • clone(): ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ€๋ฆฌํ‚ด(๋งํฌ๋กœ ์ฒ˜๋ฆฌ)
  • fork()์™€ pthread_create()๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฒฐ๊ตญ clone()์„ ํ˜ธ์ถœ
This post is licensed under CC BY 4.0 by the author.