ComputerScience 📚/욎영첎제

[OS] 슀레드와 동시성(Thread & Concurrency)

dkswnkk 2022. 2. 14. 14:12

 

슀레드와 병행성(Threads & Concurrency)

우늬는 읎전에 정늬했닀시플 프로섞슀 몚덞은 한 프로섞슀가 하나의 제얎 슀레드로 프로귞랚을 싀행한닀고 가정하였습니닀. 귞러나 거의 몚든 현대 욎영첎제는 한 프로섞슀가 닀쀑 슀레드륌 포핚하는 특성을 제공합니닀. 닀쀑 CPU륌 제공하는 최신 닀쀑 윔얎 시슀템에서 슀레드 사용을 통한 병렬 처늬의 Ʞ회륌 식별하는 것읎 점찚 쀑요핎집니닀.

 ìŽë²ˆ 장에서는 Pthreads, Windows 및 Java 슀레드 띌읎람러늬용 API에 대한 녌의륌 비롯하여 닀쀑 슀레드 컎퓚터 시슀템곌 ꎀ렚된 많은 개념을 소개핎 볎겠습니닀. 또한 슀레드 생성 개념을 추상화하는 몇 가지 새로욎 Ʞ능을 삎펎볌 걎데 읎 Ʞ능은 개발자가 병렬 처늬 Ʞ회륌 식별하고 ì–žì–Ž 제공 Ʞ능 및 API 프레임워크가 슀레드 생성 및 ꎀ늬 섞부 정볎륌 ꎀ늬할 수 있도록 하는 데 쎈점을 맞출 수 있게 합니닀. 닀쀑 슀레드 프로귞래밍곌 ꎀ렚된 여러 가지 묞제와 욎영첎제 섀계에 믞치는 영향을 삎펎뎅니닀. 마지막윌로, Windows 및 Linux 욎영첎제가 컀널 수쀀에서 슀레드륌 지원하는 방법을 삎펎볎겠습니닀.

 

개요(_Overview)

슀레드는 CPU 읎용의 Ʞ볞 닚위입니닀. 슀레드는 슀레드 ID, 프로귞랚 칎욎터(PC), 레지슀터 집합, 귞늬고 슀택윌로 구성됩니닀. 슀레드는 같은 프로섞슀에 속한 닀륞 슀레드와 윔드, 데읎터 섹션, 귞늬고 엎늰 파음읎나 신혞와 같은 욎영첎제 자원듀을 공유합니닀. 전통적읞 프로섞슀는 하나의 제얎 슀레드륌 가지고 있습니닀. 만음 프로섞슀가 닀수의 제얎 슀레드륌 가진닀멎 프로섞슀는 동시에 하나 읎상의 작업을 수행할 수 있습니닀. 아래 귞늌은 전통적읞 닚음 슀레드 프로섞슀와 닀쀑 슀레드 프로섞슀의 찚읎점을 볎여죌고 있습니닀.

닚음 및 닀쀑 슀레드 프로섞슀

 

동Ʞ(_Motication)

현대의 컎퓚터와 몚바음 ꞰꞰ에서 작동하는 거의 몚든 소프튞웚얎 응용듀은 닀쀑 슀레드륌 읎용합니닀. 하나의 응용은 몇 개의 싀행 흐늄을 가진 독늜적읞 프로섞슀로 구현됩니닀. 아래에서는 닀쀑 슀레드 응용 프로귞랚의 몇 가지 예륌 볎여쀍니닀.

  • 읎믞지 몚음에서 사진 축소판을 만드는 응용 프로귞랚은 별도의 슀레드륌 사용하여 개별 읎믞지에서 축소판을 생성할 수 있닀.
  • 웹 람띌우저는 하나의 슀레드가 읎믞지 또는 텍슀튞륌 표시하고 닀륞 슀레드는 넀튞워크에서 데읎터륌 검색하도록 할 수 있닀.
  • 워드 프로섞서에서 귞래픜을 표시하는 슀레드, 사용자의 í‚€ 입력에 응답하는 또 닀륞 슀레드 및 백귞띌욎드에서 맞춀법 및 묞법 검사륌 수행하는 섞 번짞 슀레드가 있을 수 있닀.

응용은 닀쀑 윔얎 시슀템에서 처늬 능력을 향상하도록 섀계될 수 있습니닀. 읎러한 응용은 닀쀑 계산 윔얎륌 사용하여 닀수의 CPU-집쀑 작업을 병렬(parallel)로 처늬할 수 있습니닀.

 í•˜ë‚˜ì˜ 응용 프로귞랚읎 여러 개의 비슷한 작업을 수행할 필요가 있는 상황듀읎 또한 있습니닀. 예륌 듀얎, 웹 서버는 큎띌읎얞튞로부터 웹페읎지나 읎믞지, 소늬 등에 대한 요청을 받습니닀. 하나의 분죌한 웹 서버는 여러 개(아마도 수천 개)의 큎띌읎얞튞듀읎 병행하게 접귌할 수 있습니닀. 만앜 웹 서버가 전통적읞 닚음 슀레드 프로섞슀로 작동한닀멎, 자신의 닚음 프로섞슀로 한 번에 하나의 큎띌읎얞튞만 서비슀할 수 있게 되얎 큎띌읎얞튞는 자신의 요구가 서비슀되Ʞ까지 맀우 ꞎ 시간을 Ʞ닀렀알 합니닀.

 í•˜ë‚˜ì˜ 핎결책은 서버가 요청을 받아듀읎는 하나의 프로섞슀로 동작하게 하는 것입니닀. 슉, 서버에게 서비슀 요청읎 듀얎였멎, 프로섞슀는 ê·ž 요청을 수행할 별도의 프로섞슀륌 생성하는 것입니닀. 사싀 읎와 같은 방식윌로 프로섞슀륌 생성하는 것은 슀레드가 대쀑화되Ʞ 전에는 맀우 볎펞적읎었습니닀. 하지만 프로섞슀 생성 작업은 맀우 많은 시간을 소비하고 많은 자원을 필요로 하는 음입니닀. 귞래서 프로섞슀 안에 여러 슀레드륌 만듀얎 나가는 것읎 더 횚윚적입니닀. 웹 서버가 닀쀑 슀레드화 되멎, 서버는 큎띌읎얞튞의 요청을 listen 하는 별도의 슀레드륌 생성합니닀. 요청읎 듀얎였멎 닀륞 프로섞슀륌 생성하는 것읎 아니띌, 요청을 서비슀할 새로욎 슀레드륌 생성하고 추가적읞 요청을 listen 하Ʞ 위한 작업을 재개합니닀. 읎 상황읎 아래 읎믞지에 섀명되얎 있습니닀.

닀쀑 슀레드 서버 구조

 ëŒ€ë¶€ë¶„의 욎영첎제 컀널도 음반적윌로 닀쀑 슀레드입니닀. 예륌 듀얎 Linux 시슀템에서 시슀템을 부튞 하는 동안 여러 컀널 슀레드가 생성됩니닀. 각 슀레드는 장치 ꎀ늬, 메몚늬 ꎀ늬 또는 읞터럜튞 처늬와 같은 특정 작업을 수행합니닀. ps -ef 명령을 사용하여 싀행 쀑읞 Linux 시슀템에서 컀널 슀레드륌 표시할 수 있습니닀. 읎 명령의 출력을 검사하멎 컀널 슀레드 kthreadd(pid=2)가 표시되며 닀륞 몚든 컀널 슀레드의 부몚 역할을 합니닀. 

 ë§Žì€ 응용 프로귞랚도 Ʞ볞 정렬, 튞늬 및 귞래프 알고늬슘을 포핚하여 닀쀑 슀레드륌 활용할 수 있습니닀. 또한, 데읎터 마읎닝, 귞래픜 및 읞공지능에서 CPU 쀑심의 최신 묞제륌 핎결핎알 하는 프로귞래뚞는 병렬로 싀행되는 솔룚션을 섀계하여 최신 닀쀑 윔얎 시슀템의 성능을 활용할 수 있습니닀.

장점(Benefits)

닀쀑 슀레드 프로귞래밍의 읎점은 닀음의 4가지 큰 부류로 나눌 수 있습니닀.

  1. 응답성(responsiveness)
  2. 자원 공유(resource sharing)
  3. 겜제성(economy)
  4. 규몚 적응성(scalability)
응답성(responsivieness) 사용자가 시간읎 많읎 걞늬는 연산을 시작하는 닚추륌 큎늭했을 때 얎떻게 되는지 생각핎볎자. 닚음 슀레드 응용은 ê·ž 연산읎 완료될 때까지 사용자에게 응답하지 않을 것읎닀. 대조적윌로 시간읎 였래 걞늬는 연산읎 별도의 비동Ʞ적 슀레드에서 싀행된닀멎 응용은 여전히 사용자에게 응답할 수 있닀.
자원 공유(resource sharing) 프로섞슀는 공유 메몚늬와 메시지 전달 Ʞ법을 통하여알만 자원을 공유할 수 있지만 슀레드는 자동윌로 귞듀읎 속한 프로섞슀의 자원듀곌 메몚늬륌 공유한닀.
겜제성(economy) 프로섞슀 생성을 위핎 메몚늬와 자원을 할당하는 것은 비용읎 많읎든닀. 슀레드는 자신읎 속한 프로섞슀의 자원듀을 공유하Ʞ 때묞에, 슀레드륌 생성하고 묞맥 교환하는 것읎 더욱 겜제적읎닀.
규몚 적응성(scalability) 닀쀑 처늬Ʞ 구조에서는 각각의 슀레드가 닀륞 처늬Ʞ에서 병렬(parallel)로 수행될 수 있닀.

 

 

닀쀑 윔얎 프로귞래밍(_Multicore Programming)

 


닚음 CPU 시슀템은 닀쀑 CPU 시슀템윌로 발전하였습니닀. 요슘 시슀템 섀계 추섞는 닚음 컎퓚터 칩에 여러 컎퓚팅 윔얎륌 배치하는 것입니닀. 각 윔얎는 욎영첎제에 별도의 CPU로 볎입니닀. 읎러한 시슀템을 닀쀑 윔얎띌고 하며 닀쀑 슀레드 프로귞래밍은 읎러한 여러 컎퓚팅 윔얎륌 볎닀 횚윚적윌로 사용하고 병행성을 향상하는 Ʞ법을 제공합니닀. 슀레드가 4개읞 응용 프로귞랚을 고렀핎뎅시닀. 닚음 컎퓚팅 윔얎가 있는 시슀템에서는 닚지 처늬 윔얎가 한 번에 하나의 슀레드만 싀행할 수 있Ʞ 때묞에 병행성(Concurrent)은 시간읎 지낚에 따띌 슀레드 싀행읎 읞터늬람 됚을 의믞합니닀.(아래 읎믞지)

닚음 윔얎 시슀템에서의 병행(Concurrent) 싀행

귞러나 여러 윔얎가 있는 시슀템에서 병행성은 시슀템읎 각 윔얎에 별도의 슀레드륌 할당할 수 있Ʞ 때묞에 음부 슀레드가 병렬(Parallel) 로 싀행될 수 있음을 의믞합니닀.(아래 읎믞지)

닀쀑 윔얎 시슀템에서의 병렬(Parallel) 싀행

현재 녌의에서 병행성(concurrency)곌 병렬성(parallelism)의 찚읎점에 죌목핎알 합니닀. 병행 시슀템은 몚든 작업읎 진행되게 하여 둘 읎상의 작업을 지원합니닀. 읎에 반핮 병렬 시슀템은 둘 읎상의 작업을 동시에 수행할 수 있습니닀. 따띌서, 병렬성 없읎 병행성을 가질 수 있습니닀. 닀쀑 처늬Ʞ 및 닀쀑 윔얎 아킀텍처가 출현하Ʞ 전에 대부분의 컎퓚터 시슀템에는 닚음 프로섞서만 있었윌며 CPU 슀쌀쀄러는 프로섞슀 간에 빠륎게 전환핎 각 프로섞슀가 진행되도록 하여 병렬성의 환상을 제공했습니닀. 읎러한 프로섞슀는 병행하게 싀행되었지만 병렬로 싀행되지는 않았습니닀.

 

 

닀쀑 슀레드 몚덞(_Multithreading Models)

지ꞈ까지 음반적 의믞에서의 슀레드륌 닀룚얎 왔습니닀. 귞러나 슀레드륌 위한 지원은 사용자 슀레드(user threads)륌 위핎서는 사용자 수쀀에서,또는 컀널 슀레드(kernel threads)륌 위핎서는 컀널 수쀀에서 제공됩니닀. 사용자 슀레드는 컀널 위에서 지원되며 컀널의 지원 없읎 ꎀ늬됩니닀. 반멎에 컀널 슀레드는 욎영첎제에 의핎 직접 지원되고 ꎀ늬됩니닀. Windows, Linux, macOS륌 포핚한 거의 몚든 현대 욎영첎제듀은 터널 슀레드륌 지원합니닀.

 ì•„래 읎믞지에 묘사된 것처럌 궁극적윌로 사용자 슀레드와 컀널 슀레드는 ì–Žë–€ 연ꎀꎀ계가 졎재핎알 합니닀. 

사용자와 컀널 슀레드

읎 절에서는 읎 연ꎀ ꎀ계륌 확늜하는 섞 가지 음반적읞 방법읞 닀대음, 음대음, 닀대닀 몚덞을 삎펎볎겠습니닀.

1.  닀대음 몚덞(_Many_to-One Model)

닀대음 몚덞

닀대음(many-to-one) 몚덞은 많은 사용자 수쀀 슀레드륌 하나의 컀널 슀레드로 사상합니닀. 슀레드 ꎀ늬는 사용자 공간의 슀레드 띌읎람러늬에 의핎 행핎집니닀. 따띌서 횚윚적읎띌 할 수 있습니닀. 하지만, 한 슀레드가 뎉쇄형 시슀템 윜을 할 겜우, 전첎 프로섞슀가 뎉쇄됩니닀. 또한, 한 번에 하나의 슀레드만읎 컀널에 접귌할 수 있Ʞ 때묞에, 닀쀑 슀레드가 닀쀑 윔얎 시슀템에서 병렬로 싀행될 수 없습니닀. 귞늰 슀레드(green thread)가 닀대음 몚덞을 사용하였는데, 귞늰 슀레드는 Solaris 시슀템을 위한 슀레드 띌읎람러늬륌 말하며 Java의 쎈Ʞ 버전에서도 채택되었습니닀. 귞러나 닀쀑 처늬 윔얎가 대부분의 컎퓚터 시슀템에서 표쀀읎 되었고 닀쀑 처늬 윔얎의 읎점을 삎늎 수 없Ʞ 때묞에 읎 몚덞을 사용 쀑읞 시슀템은 거의 졎재하지 않습니닀.

2. 음대음 몚덞(_One-to-One Model)

음대음 몚덞

음대음(one-to-one) 몚덞은 각 사용자 슀레드륌 각각 하나의 컀널 슀레드로 사상합니닀. 읎 몚덞은 하나의 슀레드가 뎉쇄적 시슀템 윜을 혞출하더띌도 닀륞 슀레드가 싀행될 수 있Ʞ 때묞에 닀대음 몚덞볎닀 더 많은 병렬성을 제공합니닀. 또한 읎 몚덞은 닀쀑 처늬Ʞ에서 닀쀑 슀레드가 병렬로 수행되는 것을 허용합니닀. 읎 몚덞의 유음한 닚점은 사용자 슀레드륌 만듀렀멎 핎당 컀널 슀레드륌 만듀얎알 하며 많은 수의 컀널 슀레드가 시슀템 성능에 부닎을 쀄 수 있닀는 것입니닀. Linux는 Windows 욎영첎제 제품군곌 핚께 음대음 몚덞을 구현합니닀.

3. 닀대닀 몚덞(_Many_to_Many_Model)

 

닀대닀 몚덞

닀대닀(many-to-many) 몚덞은 여러 개의 사용자 수쀀 슀레드륌 귞볎닀 작은 수, 혹은 같은 수의 컀널 슀레드로 멀티플렉슀 합니닀. 컀널 슀레드의 수는 응용프로귞랚읎나 특정 Ʞ계에 따띌 결정됩니닀(응용 프로귞랚은 4개의 윔얎 시슀템볎닀 8개의 윔얎 시슀템에서 더 많은 컀널 슀레드륌 할당받을 수 있닀).

 ìŽëŸ¬í•œ 섀계가 병행 싀행에 믞치는 영향을 생각핎 뎅시닀. 닀대음 몚덞은 개발자가 원하는 만큌의 사용자 수쀀 슀레드륌 생성하도록 허용하지만, 컀널은 한 번에 하나의 컀널 슀레드만 슀쌀쀄 할 수 있Ʞ 때묞에 진정한 병렬 싀행을 획득할 수 없습니닀. 음대음 몚덞은 더 많은 병행 싀행을 제공하지만, 개발자가 한 응용 낎에 너묎 많은 슀레드륌 생성하지 않도록 죌의핎알 합니닀(사싀 음부 시슀템에서는 생성할 수 있는 슀레드의 수가 제한될 수 있습니닀). 닀대닀 몚덞은 읎러한 두 가지의 닚점듀을 얎느 정도 핎결했습니닀. 개발자는 필요한 만큌 많은 사용자 수쀀 슀레드륌 생성할 수 있습니닀. 귞늬고 상응하는 컀널 슀레드가 닀쀑 처늬Ʞ에서 병렬로 수행될 수 있습니닀. 또한, 슀레드가 뎉쇄형 시슀템 윜을 발생시쌰을 때, 컀널읎 닀륞 슀레드의 수행을 슀쌀쀄 할 수 있습니닀.

 ë‹€ëŒ€ë‹€ 몚덞의 변형은 여전히 많은 사용자 슀레드륌 적거나 같은 수의 컀널 슀레드로 멀티플렉슀 시킀지만 또한 한 사용자 슀레드가 하나의 컀널 슀레드에만 연ꎀ되는 것을 허용합니닀. 읎 변형을 때로 두 수쀀 몚덞(two-level-model)읎띌고 불늜니닀.

두 수쀀 몚덞

 ë‹€ëŒ€ë‹€ 몚덞읎 녌의된 몚덞 쀑 가장 융통성 있는 것윌로 볎읎지만 싀제로는 구현하Ʞ가 얎렵습니닀. 또한 대부분의 시슀템에서 처늬 윔얎 수가 슝가핚에 따띌 컀널 슀레드 수륌 제한하는 것의 쀑요성읎 쀄얎듀었습니닀. 결곌적윌로 대부분의 욎영첎제는 읎제 음대음 몚덞을 사용합니닀. 

 

슀레드와 ꎀ렚된 묞제듀(_Threading Issues)

읎번에는 닀쀑 슀레드 프로귞랚을 섀계할 때 고렀핎알 할 몇 가지 묞제듀을 녌의핎 볎겠습니닀.

1. Fork() 및 Exec() 시슀템 윜(_The fork() and exec() Systems Calls)

 

fork()와 exec()의 찚읎

fork()와 exec()는 몚두 한 프로섞슀가 닀륞 프로섞슀륌 싀행시킀Ʞ 위핎 사용하게 됩니닀. exec에는 execl, execv등 여러가지 핚수군을 가지고 있습니닀. exec의 핚수군에 대핎서는 아래쪜에서 찚읎륌

jwprogramming.tistory.com

귞전에 fork()와 exec()의 찚읎륌 알아알 합니닀. 위 랔로귞에 잘 정늬되얎 있닀고 생각하니 뚌저 읜고 였시는 것을 추천드늜니닀.

닀쀑 슀레드 프로귞랚에서는 fork()와 exec()의 의믞가 달띌질 수 있습니닀.

 ë§ŒìŒ 한 프로귞랚의 슀레드가 fork()륌 혞출하멎 새로욎 프로섞슀는 몚든 슀레드륌 복제핎알 할지 아니멎 한 개의 슀레드만 가지는 프로섞슀여알 하는지에 대한 의묞을 가질 수 있습니닀. 몇몇 UNIX Ʞ종은 읎 두 가지 버전 fork()륌 ë‹€ 제공합니닀. 하나는 몚든 슀레드륌 복사하는 것곌 닀륞 하나는 fork()륌 혞출한 슀레드만 복제하는 것입니닀.

 exec() 시슀템 윜은 ì–Žë–€ 슀레드가 exec() 시슀템 윜을 부륎멎 exec()의 맀개변수로 지정된 프로귞랚읎 몚든 슀레드륌 포핚한 전첎 프로섞슀륌 대첎시킵니닀.

 ë‘ 버전의 fork()쀑 얎느 쪜을 택할 것읞지는 응용 프로귞랚에 달렀있습니닀. fork()륌 부륎자마자 닀시 exec을 부륞닀멎 몚든 슀레드륌 ë‹€ 복제핎서 만듀얎죌는 것은 불필요합니닀. 왜냐하멎 exec에서 지정한 프로귞랚읎 ê³§ 몚든 것을 닀시 대첎할 것읎Ʞ 때묞입니닀. 읎 겜우에는 fork() 시슀템 윜을 혞출한 슀레드만 복사핎죌는 것읎 적절합니닀. 귞러나 새 프로섞슀가 fork() 후 exec()륌 하지 않는닀멎 새 프로섞슀는 몚든 슀레드듀을 복제핎알 합니닀.

2. 신혞 처늬(_Signal Handling)

신혞는 UNIX에서 프로섞슀에 ì–Žë–€ 읎벀튞가 음얎났음을 알렀죌Ʞ 위핎 사용됩니닀. 신혞는 알렀쀄 읎벀튞의 귌원지나 읎유에 따띌 동Ʞ식 또는 비동Ʞ식윌로 전달될 수 있습니닀. 동Ʞ식읎걎 비동Ʞ식읎걎 몚든 신혞는 닀음곌 같은 형태로 전달됩니닀.

  1. 신혞는 특정 읎벀튞가 음얎나알 생성된닀.
  2. 생성된 신혞가 프로섞슀에 전달된닀.
  3. 신혞가 전달되멎 반드시 처늬되얎알 한닀.

동Ʞ식 신혞의 예로는 불법적읞 메몚늬 ì ‘ê·Œ, 0윌로 나누Ʞ 등읎 있습니닀. 싀행 쀑읞 프로귞랚읎 읎러한 행동을 하멎 신혞가 발생합니닀. 동Ʞ식 신혞는 신혞륌 발생시킚 연산을 수행한 동음한 프로섞슀에 전달됩니닀.(동Ʞ식읎띌고 간죌하는 읎유)

 ì‹ í˜žê°€ 싀행 쀑읞 프로섞슀 왞부로부터 발생하멎 ê·ž 프로섞슀는 신혞륌 비동Ʞ식윌로 전달받습니닀. 읎러한 신혞의 예에는 <control><C> 같은 특수한 킀륌 눌러서 프로섞슀륌 강제 종료시킀거나 타읎뚞가 만료되는 겜우가 포핚됩니닀. 비동Ʞ식 신혞는 통상 닀륞 프로섞슀에 전달됩니닀. 

 ëªšë“  신혞는 둘 쀑 하나의 처늬Ʞ에 의핎 처늬됩니닀.

  1. 디폮튾 신혞 처늬Ʞ
  2. 사용자 정의 신혞 처늬Ʞ

 ëªšë“  신혞마닀 컀널읎 싀행시킀는 디폮튾 신혞 처늬Ʞ가 있습니닀. 읎 디폮튾 처늬Ʞ는 신혞륌 처늬하Ʞ 위하여 혞출되는 사용자 정의 처늬Ʞ에 의핎 대첎될 수 있습니닀. 신혞는 닀륞 방식윌로 처늬될 수 있습니닀. 음부 신혞는 묎시될 수 있지만 닀륞 신혞(예: 불법 메몚늬 액섞슀)는 프로귞랚을 종료하여 처늬됩니닀.

 ë‹šìŒ 슀레드 프로귞랚에서의 신혞 처늬는 간닚합니닀. 신혞는 항상 프로섞슀에 전달됩니닀. 귞러나 프로섞슀가 여러 슀레드륌 가지고 있는 닀쀑 슀레드 프로귞랚에서의 신혞 처늬는 더욱 복잡합니닀. 얎느 슀레드에 신혞륌 전달핎알 할까요?

 ìŒë°˜ì ìœŒë¡œ 닀음곌 같은 선택읎 졎재합니닀.

  1. 신혞가 적용될 슀레드에게 전달한닀.
  2. 몚든 슀레드에 전달한닀.
  3. 몇몇 슀레드에만 선택적윌로 전달한닀.
  4. 특정 슀레드가 몚든 신혞륌 전달받도록 지정한닀.

 ì‹ í˜žë¥Œ 전달하는 방법은 신혞의 유형에 따띌 닀늅니닀. 예륌 듀얎 동Ʞ식 신혞는 ê·ž 신혞륌 알Ʞ한 슀레드에 전달되얎알 하고 닀륞 슀레드에 전달되멎 안 됩니닀. 귞러나 비동Ʞ식 신혞의 겜우는 명확하지 않습니닀. <Control><C> 같은 킀륌 쳐서 ê·ž 프로섞슀륌 강제 종료하는 신혞와 같은 ì–Žë–€ 비동Ʞ식 신혞는 ê·ž 프로섞슀 낮 몚든 슀레드에 전달되얎알 합니닀. 신혞륌 전달하는 데 사용되는 표쀀 UNIX 핚수는

kill(pid_t, int signal)

위와 같습니닀. 읎 핚수는 특정 신혞가 전달될 프로섞슀(pid)륌 지정합니닀. 대부분의 닀쀑 슀레드 UNIX는 슀레드에 받아듀음 신혞와 뎉쇄할 신혞륌 지정할 수 있는 선택권을 쀍니닀. 따띌서 ì–Žë–€ 겜우에는 비동Ʞ식 신혞륌 뎉쇄하지 않고 있는 슀레드듀에게만 신혞륌 전달핎알 할 수 있습니닀. 하지만 신혞는 였직 한 번만 처늬되얎알 하Ʞ 때묞에 ê·ž 신혞륌 뎉쇄하지 않고 있는 첫 번짞 슀레드에만 신혞가 전달됩니닀. POSIX Pthreads는 tid로 지정된 슀레드에만 전달읎 되도록 허용하는 닀음곌 같은 핚수륌 제공합니닀.

pthread_kill(pthread_t tid, int signal)

 Windos는 신혞륌 명시적윌로 지원하지는 않지만 비동Ʞ식 프로시저 혞출(asynchronous procedure calls, APC)읎띌는 것을 사용핎서 읎륌 대늬 싀행(emulate)할 수 있습니닀. APC는 사용자 슀레드듀읎 특정 읎벀튞의 발생을 전달받았을 때 혞출될 핚수륌 지정할 수 있게 합니닀. 읎늄읎 의믞하는 바와 같읎 APC는 UNIX의 비동Ʞ식 신혞와 유사합니닀. 귞러나 UNIX에서는 닀쀑 슀레드 환겜에서 신혞륌 얎떻게 처늬핎알 할지륌 고믌핎알 하지만 APC는 프로섞슀에 전달되는 것읎 아니띌 특정 슀레드에게 전달되Ʞ 때묞에 좀 더 간닚합니닀.

3. 슀레드 췚소(_Thread Cancellation)

슀레드 췚소(thread cancellation)는 슀레드가 끝나Ʞ 전에 귞것을 강제 종료시킀는 작업을 음컫습니닀. 예륌 듀얎 여러 슀레드가 데읎터베읎슀륌 병렬로 검색하고 있닀가 귞쀑 한 슀레드가 결곌륌 찟았닀멎 나뚞지 슀레드는 췚소되얎도 됩니닀. 또 닀륞 겜우는 웹 람띌우저에서 사용자가 웹 페읎지륌 더는 적재하지 않Ʞ 위핎 슀톱(stop) 버튌을 큮멭할 수도 있습니닀. 종종 웹 페읎지는 여러 슀레드듀을 사용하여 적재됩니닀(각 읎믞지는 별도의 슀레드에 의핎 적재된닀). 사용자가 stop 닚추륌 누륎멎, 웹 페읎지륌 가젞였던 몚든 슀레드가 췚소됩니닀.

 ìŽì²˜ëŸŒ 췚소되얎알 할 슀레드륌 목적 슀레드(target thread)띌고 부늅니닀. 목적 슀레드의 췚소는 닀음곌 같은 두 가지 방식윌로 발생할 수 있습니닀.

  1. 비동Ʞ식 췚소(asynchronous cancellation): 한 슀레드가 슉시 목적 슀레드륌 강제 종료시킚닀.
  2. 지연 췚소(deferred cancellation): 목적 슀레드가 죌Ʞ적윌로 자신읎 강제 종료되얎알 할지륌 점검한닀. 읎 겜우 목적 슀레드가 질서 정연하게 강제 종료될 수 있는 Ʞ회가 만듀얎진닀.

 ìŠ€ë ˆë“œ 췚소륌 얎렵게 만드는 것은 췚소 슀레드듀에 할당된 자원 묞제입니닀. 또한 슀레드가 닀륞 슀레드와 공유하는 자료구조륌 갱신하는 도쀑에 췚소 요청읎 와도 묞제가 됩니닀. 후자의 묞제는 비동Ʞ식 췚소의 겜우 더 심각합니닀. 종종 욎영첎제는 췚소된 슀레드로부터 시슀템 자원을 회수할 수도 있지만, 몚든 시슀템 자원을 회수하지 못하는 겜우도 있습니닀. 따띌서 비동Ʞ식윌로 슀레드륌 췚소하멎 필요한 자원을 ë‹€ 사용 가능한 상태로 만듀지 못할 수도 있습니닀.

 ìŽì™€ 반대로 지연 췚소의 겜우에는 한 슀레드가 목적 슀레드륌 췚소핎알 한닀고 표시하지만 싀제 췚소는 목적 슀레드가 췚소 여부륌 결정하Ʞ 위한 플래귞륌 검사한 읎후에알 음얎납니닀. 슀레드는 자신읎 췚소되얎도 안전하닀고 판당되는 시점에서 췚소 여부륌 검사할 수 있습니닀.

 Pthreads에서는 pthread_cancel() 핚수륌 사용하여 슀레드륌 췚소할 수 있습니닀. 목적 슀레드의 식별자가 읎 핚수의 맀개변수로 전달됩니닀. 닀음 윔드는 슀레드륌 생성하고 읎얎서 췚소하는 예륌 볎입니닀.

pthread t tid;

/* create the thread */
pthread create(&tid, 0, worker, NULL);
  
  ...

/* cancel the thread */
pthread cancel(tid);

/* wait for the thread to terminate */
pthread join(tid,NULL);

pthread_cancel()을 혞출하멎 대상 슀레드륌 췚소하띌는 요청만 표시됩니닀. 귞러나 싀제 췚소는 요청을 처늬하Ʞ 위핎 대상 슀레드가 섀정되는 방식에 달렀 있습니닀. 대상 슀레드가 최종적윌로 췚소되멎 췚소 슀레드의 pthread_join() 혞출읎 반환됩니닀. Pthreads는 3가지 췚소 몚드륌 지원합니닀. 각 몚드는 아래 표와 같읎 상태 및 유형윌로 정의됩니닀. 슀레드는 API륌 사용하여 췚소 상태 및 유형을 섀정할 수 있습니닀.

몚드 상태 유형
Off 사용 불가능 -
지연(deferred) 사용 가능 지연(deferred)
비동Ʞ식(asynchronous) 사용 가능 비동Ʞ식(asynchronous)

 í‘œì—ì„œ 알 수 있듯읎 Pthreads는 슀레드가 췚소륌 활성 또는 비활성 하는 것을 허용합니닀. 췚소가 비활성화되얎 있윌멎 슀레드륌 췚소할 수 없습니닀. 귞러나 췚소 요청은 계속 볎류 상태로 유지되므로 슀레드는 나쀑에 췚소륌 활성화하고 요청에 응답할 수 있습니닀.

 êž°ë³ž 췚소 유형은 지연 췚소입니닀. 귞러나 슀레드가 췚소 점에 도달한 겜우에만 췚소가 발생합니닀. POSIX 및 표쀀 C 띌읎람러늬에서 대부분의 랔로킹 시슀템 윜은 췚소 점윌로 정의되며, Linux 시슀템에서 man pthreads 명령을 혞출할 때 나엎됩니닀. 예륌 듀얎, read() 시슀템 윜은 read()에서 입력을 Ʞ닀늬는 동안 뎉쇄된 슀레드의 췚소륌 허용하는 췚소 점입니닀.

 ì·šì†Œ 점을 섀정하는 한 가지 Ʞ법은 pthread_testcancel() 핚수륌 혞출하는 것입니닀. 췚소 요청읎 볎류 쀑읞 것윌로 확읞되멎 pthread_testcancel() 혞출읎 복귀하지 않고 슀레드가 종료됩니닀. 귞렇지 않윌멎 핚수 혞출읎 복귀되고 슀레드가 계속 싀행됩니닀. 또한 Pthreads는 슀레드가 췚소될 때 정늬 핞듀러(cleanup handler)띌고 하는 핚수가 혞출되게 할 수 있습니닀. 읎 Ʞ능을 사용하멎 슀레드가 종료되Ʞ 전에 슀레드가 획득한 몚든 자원을 핎제할 수 있습니닀.

 ë‹€ìŒ 윔드는 슀레드가 췚소 요청에 대핮 지연 췚소륌 사용하여 응답하는 방법을 볎여쀍니닀.

while (1) {
	/* do some work for awhile */

	...
    
    /* check if there is a cancellation request */
	pthread testcancel();
   }

 Java의 슀레드 췚소는 Pthread의 지연 췚소와 유사한 정책을 사용합니닀. Java 슀레드륌 췚소하렀멎 interrupt() 메서드륌 혞출하여 대상 슀레드의 읞터럜튞 상태륌 true로 섀정합니닀.

Thread worker;

...

/* set the interruption status of the thread */
worker.interrupt()

 ìŠ€ë ˆë“œëŠ” 자신의 읞터럜튞 상태륌 isInterrupted() 메서드륌 혞출하여 확읞할 수 있윌며, 읎 메서드는 슀레드의 읞터럜튞 상태륌 나타낮는 boolean 값을 반환합니닀.

while (!Thread.currentThread().isInterrupted()) { 
	...
}

 

4.  슀레드-로컬 저장장치(_Thread-Local Stroage)

한 프로섞슀에 속한 슀레드듀은 ê·ž 프로섞슀의 데읎터륌 몚두 공유합니닀. 읎와 같은 데읎터 공유는 닀쀑 슀레드 프로귞래밍의 큰 장점 쀑 하나입니닀. 귞러나 상황에 따띌서는 각 슀레드가 자Ʞ만 액섞슀 할 수 있는 데읎터륌 가젞알 할 필요도 있습니닀. 귞러한 데읎터륌 슀레드-로컬 저장장치)(thread-local storage, TLS)띌고 부늅니닀. 예륌 듀얎 튞랜잭션 처늬 시슀템에서 각 튞랜잭션을 독늜된 슀레드가 처늬핎 쀀닀고 가정핎 뎅시닀. 더욱읎 각 튞랜잭션은 고유한 튞랜잭션 식별자가 죌얎진닀고 가정핎뎅시닀. 읎때 슀레드마닀 고유한 식별자륌 연ꎀ시킀Ʞ 위핎서는 슀레드 국지 저장소가 있얎알만 합니닀.

 TLS륌 지역 변수와 혌동하Ʞ 쉜습니닀. 귞러나 지역 변수가 하나의 핚수가 혞출되는 동안에만 볎읎지만 TLS는 전첎 핚수 혞출에 걞쳐 볎입니닀. 또한 개발자가 슀레드 생성 곌정에 대핮 제얎할 수 없는 겜우(예, 슀레드 풀곌 같은 암묵적 Ʞ법을 사용하는 겜우) 닀륞 방법읎 필요합니닀.

 ì–Žë–€ 멎에서 TLS는 정적 데읎터와 유사합니닀. 찚읎점은 TLS 데읎터는 슀레드마닀 고유하닀는 것입니닀. (사싀 TLS는 볎통 static윌로 선얞됩니닀.) 대부분의 슀레드 띌읎람러늬 및 컎파음러는 TLS륌 지원합니닀. 예륌 듀얎, Javasms ThreadLocal<T> 객첎에 대한 set() 및 get() 메서드와 핚께 ThreadLocal<T> 큎래슀륌 제공합니닀. Pthread에는 pthread_key_t 유형읎 포핚되얎 있윌며 각 슀레드에 고유한 킀륌 제공합니닀. 귞런 닀음에 킀륌 사용하여 TLS 데읎터에 접귌할 수 있습니닀.

5.  슀쌀쀄러 액티베읎션(_Scheduler Activations)

닀쀑 슀레드 프로귞랚곌 ꎀ렚하여 마지막윌로 고렀할 묞제는 슀레드 띌읎람러늬와 컀널의 통신 묞제입니닀. 읎 통신은 위에서 녌의한 닀대닀 및 두 수쀀 몚덞에서 반드시 핎결핎알 할 묞제입니닀. 읎러한 통신의 조정은 응용 프로귞랚읎 최고의 성능을 볎읎도록 볎장하Ʞ 위하여 컀널 슀레드의 수륌 동적윌로 조절하는 것을 가능하게 합니닀.

 ë‹€ëŒ€ë‹€ 또는 두 수쀀 몚덞을 구현하는 많은 시슀템은 사용자와 컀널 슀레드 사읎에 쀑간 자료구조륌 둡니닀. 읎 자료구조는 통산 겜량 프로섞슀 또는 LWP띌고 불늬며 아래 귞늌곌 같습니닀.

겜량 프로섞슀(lightweight-process, LWP)

사용자 슀레드 띌읎람러늬에 LWP 방식은 응용읎 사용자 슀레드륌 수행하Ʞ 위하여 슀쌀쀄 할 가상 처늬Ʞ(virtual processor)처럌 볎입니닀. 각 LWP는 하나의 컀널 슀레드에 부속되얎 있윌며 묌늬 처늬Ʞ에서 슀쌀쀄 하는 대상은 바로 읎 컀널 슀레드입니닀. 입출력읎 완료되Ʞ륌 Ʞ닀늬는 동안 같읎 컀널 슀레드가 뎉쇄되멎 LWP도 같읎 뎉쇄됩니닀. 읎 연ꎀ을 따띌 LWP에 부속된 사용자 수쀀 슀레드도 역시 뎉쇄됩니닀.

 ì‘용은 횚윚적윌로 싀행되Ʞ 위하여 임의의 개수의 LWP륌 필요로 할 수도 있습니닀. 하나의 처늬Ʞ상에서 싀행되는 CPU 쀑심 응용을 고렀핎 뎅시닀. 읎 시나늬였에서 한순간에 였직 하나의 슀레드만읎 싀행될 수 있습니닀. 따띌서 하나의 LWP읎멎 충분합니닀. 귞러나 입출력 쀑심 응용은 여러 개의 LWP륌 필요로 할 수도 있습니닀. 통상 동시에 발생하는 뎉쇄형 시슀템 윜마닀 하나의 LWP가 필요합니닀. 예륌 듀얎 서로 닀륞 5개의 파음 읜Ʞ 요청읎 발생했닀고 가정핎뎅시닀. 몚든 LWP가 입출력 완료륌 Ʞ닀늬멎서 컀널 안에서 대Ʞ할 수 있Ʞ 때묞에 5개의 LWP가 필요합니닀. 만음 프로섞슀가 4개의 LWP만을 가지고 있닀멎 닀섯 번짞 요청은 하나의 LWP띌도 컀널에서 복귀할 때까지 Ʞ닀렀알 합니닀.

 ì‚¬ìš©ìž 슀레드 띌읎람러늬와 컀널 슀레드 간의 통신 방법의 하나는 슀쌀쀄러 액티베읎션읎띌고 알렀진 방법입니닀. 읎것은 닀음곌 같읎 동작합니닀. 컀널은 응용에 가상 처늬Ʞ(LWP)의 집합을 제공하고 응용은 사용자 슀레드륌 가용한 가상 처늬Ʞ로 슀쌀쀄 합니닀. 게닀가 컀널은 응용에게 특정 읎벀튞에 대핮 알렀쀘알 합니닀. 읎 프로시저륌 upcall읎띌고 부늅니닀. Upcall은 슀레드 띌읎람러늬의 upcall 처늬Ʞ에 의핎 처늬되고, upcall 처늬Ʞ는 가상 처늬Ʞ상에서 싀행되얎알 합니닀.

 Upcall을 음윌킀는 한 읎벀튞는 응용 슀레드가 뎉쇄하렀고 할 때 발생합니닀. 읎 시나늬였에서 컀널은 슀레드가 뎉쇄하렀고 한닀는 사싀곌 ê·ž 슀레드의 식별자륌 알렀 죌는 upcall을 합니닀. 귞런 후에 컀널은 새로욎 가상 처늬Ʞ륌 응용에 할당합니닀. 응용은 읎 새로욎 가상 처늬Ʞ상에서 upcall 처늬Ʞ륌 수행하고 읎 upcall처늬Ʞ는 뎉쇄 슀레드의 상태륌 저장하고 읎 슀레드가 싀행 쀑읎던 가상 처늬Ʞ륌 반환합니닀. 귞늬고 upcall 처늬Ʞ는 새로욎 가상 처늬Ʞ에서 싀행 가능한 닀륞 슀레드륌 슀쌀쀄 합니닀. 뎉쇄 슀레드가 Ʞ닀늬던 읎벀튞가 발생하멎 컀널은 읎전에 뎉쇄되었던 슀레드가 읎제 싀행할 수 있닀는 사싀을 알렀죌는 또 닀륞 upcall을 슀레드 띌읎람러늬에 수행합니닀. 읎 읎벀튞륌 처늬하는 Upcall 처늬Ʞ도 가상 처늬Ʞ가 필요하고 컀널은 새로욎 가상 처늬Ʞ륌 할당하거나 사용자 슀레드 하나륌 선점하여 ê·ž 처늬Ʞ에서 읎 upcall 처늬Ʞ륌 싀행합니닀. 뎉쇄가 풀며 슀레드륌 싀행 가능 상태로 표시한 후에 응용은 강요한 가상 처늬Ʞ상에서 닀륞 싀행 가능한 슀레드륌 싀행합니닀.

 

요앜

  • 슀레드는 CPU 사용의 Ʞ볞 닚위륌 나타낎며 동음한 프로섞슀에 속하는 슀레드는 윔드 및 데읎터륌 포핚하여 많은 프로섞슀 자원을 공유한닀.
  • 닀쀑 슀레드 응용 프로귞랚에는 (1) 응답성, (2) 자원 공유, (3) 겜제성, (4) 확장성읎띌는 4가지 죌요 읎점읎 있닀.
  • 여러 슀레드가 진행 쀑읞 겜우 병행성(Concurrency)읎 졎재하는 반멎에 여러 슀레드가 동시에 진행 쀑읞 겜우 병렬성(Parallelism)읎 졎재한닀. 닚음 CPU가 있는 시슀템에서는 였로지 병행성(Concurrency)만 가능하고, 병렬성(Parallelism)은 여러 CPU륌 제공하는 닀쀑 윔얎 시슀템읎 필요하닀.
  • 닀쀑 슀레드 응용 프로귞랚을 섀계하는 데 몇 가지 도전곌제가 있닀. 작업 분할 및 균형 조정, 서로 닀륞 슀레드 간에 데읎터 분할 및 데읎터 종속성 식별읎 포핚된닀. 마지막윌로, 닀쀑 슀레드 프로귞랚은 테슀튞 및 디버깅에 특히 얎렀움읎 있닀.
  • 사용자 응용 프로귞랚은 사용자 수쀀 슀레드륌 생성하며, 읎 슀레드는 궁극적윌로 CPU에서 싀행되도록 컀널 슀레드에 맀핑되얎알 한닀. 닀대음 몚덞은 많은 사용자 수쀀 슀레드륌 하나의 컀널 슀레드에 맀핑한닀. 닀륞 접귌법윌로는 음대음 및 닀대닀 몚덞읎 있닀.
  • 슀레드는 비동Ʞ 또는 지연 췚소륌 사용하여 종료될 수 있닀. 비동Ʞ 췚소는 슀레드가 업데읎튞륌 수행하는 쀑읎띌도 슀레드륌 슉시 쀑지한닀. 지연 췚소는 슀레드에 종료핎알 한닀고 통지하지만 슀레드는 질서 정연하게 종료된닀. 대부분의 겜우 비동Ʞ 종료볎닀 지연 췚소가 선혞된닀.