본문 바로가기

OS/OS

공룡책 4장 스레드

반응형
SMALL

이 글은 공룡책으로 유명한 운영체제 9판을 가지고 작성한 글입니다.

다르거나 이상한 점이 있다면 댓글로 알려주시면 감사하겠습니다.


앞선 3장 프로세스 글은 하나의 프로세스가 하나의 스레드를 가지고 프로그램을 실행한다고 가정했습니다. 그러나 현대 운영체제에서는 한 프로세스에 다중 스레드를 포함하는 특성을 가집니다.

스레드란?

스레드는 CPU 이용의 기본 단위입니다. 스레드는 스레드 ID, 프로그램 카운터, 레지스터 집합, 그리고 스택으로 구성됩니다. 스레드는 같은 프로세스에 속한 다른 스레드와 코드, 데이터, 운영체제 자원들을 공유합니다. 프로세스는 하나의 스레드는 반드시 가집니다. 만약 다수의 스레드를 가지면 프로세스는 한 번에 하나 이상의 작업을 수행할 수 있습니다.

이 두 가지의 차이가 단일 스레드, 다중 스레드의 차이입니다.

동기(Motivation)

현대의 컴퓨터에선 대부분 다중 스레드를 이용합니다. 하나의 응용 소프트웨어는 몇 개의 실행 흐름을 가진 독립적인 프로세스로 구현됩니다. 크롬에서 위에 창을 많이 띄울 수 있는 것을 예시로 생각하면 됩니다.

이렇게 함으로써 하나의 응용 프로그램이 여러 개의 비슷한 작업들을 수행할 필요가 있는 상황에서 큰 도움이 될 수 있습니다.

예를들어 서버에 하나의 요청을 처리하고 있을 때, 스레드가 하나라면 클라이언트는 그 요청을 마무리 지을 때까지 요청을 새로 보낼 수 없지만, 요청을 서비스할 스레드를 생성한다면, 이 문제를 해결할 수 있습니다.

사실 이 전엔 프로세스를 하나 더 생성하는 것이 스레드를 생성하는 것보다 보편적인 일이었습니다. 다만, 프로세스 생성 작업은 매우 많은 시간과 자원을 필요로 하는 일입니다. 하지만, 새 프로세스가 해야할 일이 기존 프로세스가 하는 일과 동일하다면 이 많은 오버헤드를 감수하지 않고 프로세스 내부에 여러 스레드를 만드는 것이 더 효율적입니다.

운영체제 커널에도 다수의 스레드가 동작하고 있습니다. 장치 또는 인터럽트 처리 등의 특정 작업을 하는 스레드입니다.

강점(Benefits)

다중 스레드 프로그래밍의 이점은 다음의 4가지 큰 부류로 나눌 수 있습니다.

  • 응답성(Responsiveness) : 대화형 응용 소프트웨어를 다중 스레드화하면 응용 프로그램이 긴작업을 수행하더라도 프로그램의 수행이 계속되는 것을 허용함으로써, 사용자에 대한 응답성을 증가시킵니다. 이 특징은 사용자 인터페이스를 설계하는 데 있어 유용합니다. 만약, 사용자가 시간이 오래 걸리는 버튼을 눌렀을 때 그 버튼의 연산이 끝날 때까지 사용자의 요청을 차단하는 것이 아니라, 일을 처리하면서 별도의 스레드를 실행한다면 여전히 사용자의 요청을 처리할 수 있습니다.
  • 자원 공유(Resource sharing) : 프로세스는 공유 메모리와 메시지 전달 기법으로 자원을 공유할 수 있습니다. 이러한 기법은 프로그래머가 직접 처리해야하는 것입니다. 그러나 스레드는 자동으로 그들이 속한 프로세스 자원과 메모리를 공유할 수 있습니다. 프로세스 내에서 여러 개의 작업을 해야하는 스레드가 가지는 강점입니다.
  • 경제성(Economy) : 프로세스 생성을 위해 메모리와 자원을 할당하는 것은 비용이 많이 듭니다. 스레드는 자신이 속한 프롯스의 자원을 공유하기 때문에 스레드를 생성하고 문맥 교환하는 일이 보다 경제적입니다.
  • 규모 적응성(Scalability) : 다중 스레드의 이점은 다중 처리기 구조에서 더욱 증가할 수 있습니다. 다중 처리기 구조에서는 각각의 스레드가 다른 처리기에서 병렬로 수행될 수 있습니다. 단일 스레드 프로세스는 처리기가 아무리 많더라도 오직 한 처리기에서만 실행됩니다.

다중코어 프로그래밍

컴퓨터의 성능이 좋아지면서 단일 CPU 시스템에서 다중 CPU 시스템으로 진화해왔습니다. 최근 하나의 칩 안에 여러 계산 코어를 넣는 경향이 생기고 있습니다. 코어가 여러 CPU 칩 형태를 띠는 것을 다중코어, 다중 처리기 시스템이라 부릅니다. 다중 스레드 프로그래밍은 다중 계산 코어를 더 효율적으로 사용할 수 있고 병행 실행을 더 향상시킬 수 있는 기법을 제공합니다.

4개의 스레드로 실행되는 응용 소프트웨어를 고려하면 하나의 코어는 오직 하나의 스레드만 실행할 수 있기 때문에 단일 코어 시스템 상에서 병행성은 단순히 스레드의 실행이 시간에 따라 교대로 실행된다는 것을 의미합니다. 그러나 여러 코어를 가진 시스템에서는 시스템이 개별 스레드를 각 코어에 배정할 수 있기 때문에 병행성은 스레드들이 병렬적으로 실행될 수 있다는 것을 뜻합니다.

병행성, 병렬성의 차이를 주목해야 합니다. 하나 이상의 태스크를 동시에 수행할 수 있는 시스템에 대해 병렬적이라 합니다. 대조적으로 병행 시스템은 하나 이상의 업무를 하기 위해서 번갈아가면서 일을 해가는 것을 말합니다. 따라서 병럴 실행 없이 병행 실행이 가능합니다. 다중 코어 시스템 구조가 출현하기 전에는 대부분 하나의 처리기만을 가지고 있었고, CPU 스케줄러는 시스템의 프로세스 사이를 빠르게 오가며 모든 프로세스를 진행시켜 마치 병렬 실행하는 듯한 환상을 주도록 설계되었습니다. 이런 프로세스들은 병렬 실행이 되던 것이 아니고 병행 실행된 것입니다.

프로그래밍 도전과제

다중코어 시스템으로 응용 프로그래머는 다중코어 활용도를 높이는 능력이 필요로 해졌습니다. 즉, 병렬 실행이 되도록 여러 코어를 활용하는 스케줄링 알고리즘을 개발해야합니다.

일반적으로 다중코어 시스템을 위해 프로그래밍을 하기 위해선 5개의 극복 과제가 있습니다.

  • 태스크 인식(Identifying tasks) : 병렬을 할 수 있는 태스크로 나누는 영역을 찾는 작업이 필요합니다. 이상적으로는 태스크는 서로 독립적이고 개별 코어에서 병렬 실행이 가능해야 합니다.
  • 균형(Balance) : 병렬로 실행될 수 있는 태스크를 찾아내는 것도 중요하지만 그 전체 작업을 균등하게 나누는 것도 매우 중요합니다. 혹시라도 소외 받는 작업이 있을 수 있기 때문입니다.
  • 데이터 분리(Data Spliting) : 응용 소프트웨어가 독립된 태스크로 나누어지는 것처럼, 태스크가 접근하고 조작하는 데이터 또한 개별 코어에서 사용할 수 있도록 나누어져야 합니다.
  • 데이터 종속성(Data dependency) : 태스크가 접근하는 데이터는 둘 이상의 태스크 사이에서 종속성이 없는지 검토해야합니다. 즉, 동기화가 잘 되어야 합니다.
  • 시험 및 디버깅(Testing and debugging) : 프로그램이 다중코어에서 병롤로 실행될 때, 다양한 실행경로가 존재할 수 있기에 디버깅하는 것이 훨씬 어렵습니다.

이러한 도전 과제 때문에 좌절한 소프트웨어 개발자들이 많습니다. 그렇기에 교육자들은 점점 병렬 프로그래밍에 치중해야한다고 믿습니다.

병렬 실행의 유형

일반적으로 데이터 병렬 실행과 태스크 병렬 실행의 두 가지 유형이 존재합니다.

데이터 병렬 실행은 동일한 데이터의 부분집합을 다수의 계산 코어에 분배한 뒤 각 코어에서 동일한 연산을 실행하는 데 초점을 맞춥니다. 예를 들어 N인 배열의 내용을 더하는 경우를 생각했을 때, 단일 코어 시스템에서는 0부터 N-1까지 더하는 것을 계산해야합니다. 하지만, 듀어 코어 시스템이라 했을 때 0부터 N/2 -1까지 N/2부터 N-1까지 더하는 식으로 병렬처리를 한다면 좀 더 효율적으로 처리할 수 있습니다.

태스크 병렬 실행은 데이터가 아니라 태스크(스레드)가 다수의 코어에 분배됩니다. 각 스레드는 고유의 연산을 실행합니다. 다른 스레드들이 동일한 데이터에 대해 연산을 실행할 수 있고 혹은 서로 다른 데이터에 연산을 실행할 수도 있습니다.

근본적으로 데이터 병렬 실행은 데이터가 코어에 분배되어야 하고 태스크 병렬 실행은 태스크가 분배되어야 합니다. 그러나 현실적으론 어느 한쪽의 특성만을 가지는 응용 소프트웨어는 거의 없고 대부분 이 두 전략을 혼용합니다.


다중 스레드 모델(Multithreading Models)

일반적인 의미에서 스레드를 다뤘다면, 이젠 스레드를 두 가지로 쪼개서 얘기하겠습니다. 스레드는 사용자를 위한 사용자 스레드, 커널 수준에서 제공되는 커널 스레드가 있습니다. 사용자 스레드는 커널 위에서 지원되며 커널의 지원 없이 관리됩니다. 반면에 커널 스레드는 운영체제에 의해 직접 지원되고 관리됩니다.

궁극적으로 사용자 스레드와 커널 스레드는 어떤 연관 관계가 존재해야합니다. 세 가지 일반적인 방법으론 다대일, 일대일, 다대다 모델이 있습니다.

다대일 모델(Many to One Model)

다대일 모델은 많은 사용자 스레드가 하나의 커널 스레드를 사용합니다. 스레드 관리는 사용자 공간의 스레드 라이브러리에 의해 행해집니다. 어찌보면 효율적이지만, 한 스레드가 Block 시스템 콜을 할 경우 전체 프로세스가 봉쇄됩니다. 또한 한 번에 하나의 스레드만이 커널에 접근할 수 있기 때문에, 다중 스레드가 다중코어 시스템에서 병렬로 실행될 수 없습니다. 다중 처리 코어의 이점을 살릴 수 없기 때문에 거의 존재하지 않는 모델입니다.

일대일 모델(One to One Model)

일대일 모델은 각 사용자 스레드를 각각 하나의 커널 스레드로 연결합니다. 하나의 스레드가 Block 스레드 콜을 하더라도 다른 스레드가 실행될 수 있기 때문에 다대일 모델보다 더 많은 병렬성을 제공합니다. 또한, 이 모델은 다중 처리기에서 다중 스레드가 병렬로 수행되는 것을 허용합니다. 단 단점은 사용자 수준 스레드를 생성할 때 그에 따른 커널 스레드를 생성해야한다는 점입니다. 커널 스레드를 생성하는 오버헤드가 응용 프로그램의 성능을 저하시킬 수 있으므로, 대부분의 구현 시스템에선 지원되는 스레드의 수를 제한합니다.

다대다 모델(Many to Many Model)

다대다 모델은 여러 개의 사용자 수준 스레드를 그보다 작은 수 혹은, 같은 수의 커널 스레드를 연결합니다. 커널 스레드의 수는 응용 프로그램이나 특정 기계에 따라 결정됩니다. 이러한 설계가 병행 실행에 미치는 영향을 생각해보면, 다대일 모델은 개발자가 원하는 만큼의 사용자 수준 스레드를 생성하도록 허용하지만, 한 번에 하나의 스레드만이 커널에 의해서 스케줄 되기 때문에 진정한 병렬 실행을 획득할 수 업습니다. 일대일 모델의 경우엔 너무 많은 스레드를 생성하지 않도록 주의를 해야합니다. 다대다 모델은 이러한 두 가지의 단점들을 어느 정도 해결했습니다. 개발자는 필요한 만큼 많은 사용자 수준 스레드를 생성할 수 있으며, 그에 상응하는 커널 스레드가 다중 처리기에서 병렬로 수행될 수 있습니다. 또한 스레드가 Block 시스템 콜을 발생했을 때, 커널이 다른 스레드의 수행을 스케줄 할 수 있습니다.

다대다 모델의 경우에도 많은 사용자 스레드를 같은 수나 적은 커널 스레드로 연결하지만 보통 사용자 스레드 하나가 하나의 커널 스레드에만 연관되는 것을 허용합니다.


스레드 라이브러리

스레드 라이브러리는 프로그래머가 스레드를 생성하고 관리하기 위한 API를 제공합니다. 스레드 라이브러리를 구현하는 데에는 주된 두 가지 방법이 있습니다. 첫 째는 커널의 지원 없이 사용자 공간에서만 라이브러리를 제공하는 것입니다. 라이브러리의 모든 코드와 자료 구조를 사용자 공간에 존재시킴으로서 시스템 호출이 아닌 사용자 공간의 지역 함수를 호출하게 된다는 것을 의미합니다.

두 번째 방법은 운영체제에 의해 지원되는 커널 수준 라이브러리를 구현하는 것입니다. 이 경우, 라이브러리를 위한 코드와 자료 구조는 커널 공간에 존재합니다. 라이브러리 API를 호출하는 것은 커널 시스템 호출을 부르는 결과를 낳는 것입니다.

그 전에 스레드는 두 가지 전략을 가지고 있습니다. 비동기 스레딩과 동기 스레딩이 바로 그 것입니다.

비동기 스레딩은 부모가 자식 스레드를 생성한 후 부모는 자신의 실행을 재개하여 부모와 자식 스레드가 병행하게 실행됩니다. 각 스레드는 모든 다른 스레드와 독립적으로 실행하고 부모 스레드는 자식의 종료를 알 필요가 없습니다. 스레드가 독립적이라 스레드 사이의 데이터 공유는 거의 없습니다.

동기 스레딩은 부모 스레드가 하나 이상의 자식 스레드를 생성하고 자식 스레드 모두가 종료할 때까지 기다렸다가 자신의 실행을 재개하는 방식을 말합니다. 이 방식은 소위 포크-조인(fork-join)이라 부릅니다. 부모가 생성한 스레드는 병행하게 실행되지만 부모는 자식들의 작업이 끝날 때까지 실행을 계속할 수 없습니다. 부모 스레드는 오직 모든 자식 스레드가 조인한 후에야 실행을 재개할 수 있습니다. 통상 동기 스레딩은 스레드 사이의 상당한 양의 데이터 공유를 수반합니다. 예를 들어 부모 스레드는 자식들이 계산한 결과를 통합할 수 있습니다.


암묵적 스레딩

다중코어 처리의 성장에 다라 수천 개의 스레드를 가진 응용 소프트웨어가 등장하게 되었습니다. 응용을 설계하는 것은 사소한 일이 아닙니다.

이러한 어려움을 극복하고 다중 스레드 응용의 설계를 도와주는 한 가지 방법은 스레딩의 생성과 관리 책임을 응용 개발자로부터 컴파일러와 실행시간 라이브러리에게 넘겨주는 것입니다. 이를 암묵적 스레딩이라고 불리는 전략입니다. 암묵적 스레딩을 이용하여 다중코어 처리기를 활용할 수 있는 다중 스레드 프로그램을 설계하는 3가지 접근법을 알아봅시다.

스레드 풀

웹 서버는 요청을 받을 때마다 그 요청을 위해 새로운 스레드를 만듭니다. 새로운 스레드를 매 요청마다 만드는 것은 새로운 프로세스를 만드는 것보다 좋은 일이지만 다중 스레드 서버 역시 여러 문제를 가지고 있습니다.

첫 번째로는 서비스할 때마다 스레드를 만드는 데 소요하는 시간이나 두 번째 이슈는 모든 요청마다 새 스레드를 만들어서 서비스를 한다면 CPU 시간, 메모리 공간 같은 시스템 자원이 고갈됩니다. 이러한 문제들을 해결해 줄 수 있는 방법 중 하나가 스레드 풀입니다.

스레드 풀의 기본 아이디어는 프로세스를 시작할 때 아예 일정한 수의 스레드들을 미리 풀로 만들어두는 것입니다. 이 스레들은 평소에는 하는 일 없이 일감을 기다리고, 한 개의 요청이 들어오면 이 풀의 한 스레드에게 작업을 할당합니다. 요청을 다 해결했으면 다시 풀로 돌아가 작업을 기다립니다. 이렇게 하다가 풀에 남은 스레드가 바닥나면 서버는 가용(free) 스레드가 하나 생길 때까지 기다려야 합니다.

이와 같은 스레드 풀은 아래와 같은 장점을 가지게 됩니다.

  • 새 스레드를 만들어 주기보다 기존 스레드로 서비스해 주는 것이 더 빠릅니다.
  • 스레드 풀은 임의 시각에 존재할 스레드 개수에 제한을 둡니다. 이러한 제한은 많은 수의 스레드를 병렬 처리할 수 없는 시스템에 도움이 됩니다.
  • 태스크를 생성하는 방법을 태스크로부터 분리하면 태스크 실행을 다르게 할 수 있습니다. 예를 들어 태스크를 일정 시간 후에 실행되도록 스케줄하거나 혹은 주기적으로 실행할 수 있습니다.

스레드 풀에 있는 스레드의 개수는 CPU 수, 물리 메모리 용량, 동시 요청 클라이언트 최대 개수 등을 고려하여 정해질 수 있습니다. 동적으로도 물론 가능합니다. 시스템 부하가 적을 때 더 작은 풀을 유지하면서 메모리 소모를 줄일 수 있습니다.

OpenMP

OpenMP는 공유 메모리 환경에서 병렬 프로그래밍을 할 수 있도록 도움을 줍니다. OpenMP는 병렬로 실행될 수 있는 블록을 찾아 병렬 영역(parallel regions)이라고 부릅니다.

응용 개발자는 자신들의 코드 중 병렬 영역에 컴파일러 디렉티브를 삽입합니다. 이 디렉티브는 OpenMP 실행시간 라이브러리에 해당 영역을 병렬로 실행하라고 지시합니다.

Grand Central Dispatch(GCD)

GCD는 iOS 운영체제 기술입니다. GCD는 C 언어, API 및 실행시간 라이브러리 각각을 확장하여 조합한 기술입니다.


스레드와 관련된 문제들

다중 스레드 프로그램을 설계할 때 고려해야 할 몇 가지 문제점을 말해봅시다.

Fork() 및 Exec() 시스템 호출

fork()는 별도의 복제된 프로세스를 생성하는 데 쓰이는 라이브러리이지만 다중 스레드 프로그램에서는 fork() 의미가 달라질 수 있습니다. 만약 한 프로그램의 스레드가 fork()를 호출하면 새로운 프로세스는 모든 스레드를 복제해야 할까요 한 개의 스레드만 가지는 프로세스이어야 할까요? 몇몇 UNIX 기종은 이 두 가지 버전 fork()를 다 제공합니다. 하나는 모든 스레드를 복사하는 것과 다른 하나는 fork()를 호출한 스레드만 복제하는 것입니다.

exec() 시스템 호출은 exec()의 매개변수로 지정된 프로그램이 모든 스레드를 포함한 전체 프로세스를 대체합니다.

두 버전의 fork() 중 어느 쪽을 택할 것인지는 응용 프로그램에게 달려있지만, fork()를 부르고 exec()을 부른다면 모든 스레드를 복제해서 만드는 것은 불필요합니다. 왜냐하면 exec()에서 지정한 프로그램이 곧 모든 것을 다시 대체할 것이기 때문입니다. 이 경우 fork() 시스템 콜을 호출한 스레드만 복사해주는 것이 적절합니다. 그러나 새 프로세스 fork() 후 exec()을 하지 않는다면 새 프로세스는 모든 스레드를 복제해야 합니다.

신호 처리(Signal Handling)

신호는 UNIX에서 프로세스에게 어떤 사건이 일어났음을 알려주기 위해 사용됩니다. 신호는 알려줄 사건의 근원지나 이유에 따라 동기식 또는 비동기식으로 전달될 수 있습니다. 동기식이건 비동기식이건 모든 신호는 다음과 같은 형태로 전달됩니다.

  • 신호는 특정 사건이 일어나야 생성됩니다.
  • 생성된 신호가 프로세스에게 전달됩니다.
  • 신호가 전달되면 반드시 처리되어야 합니다.

동기식 신호의 예로는 불법적인 메모리 접근, 0으로 나누기 등이 있습니다. 실행 중인 프로그램이 이러한 행동을 하면 신호가 발생됩니다. 동기식 신호는 신호를 발생시킨 연산을 수행한 동일한 프로세스에게 전달됩니다.

신호가 실행 중인 프로세스 외부로부터 발생되면 그 프로세스는 신호를 비동기식으로 전달 받습니다. 이러한 신호의 예에는 crtl+C 같은 특수한 키를 눌러서 프로세스를 강제 종료시키거나 타이머가 만료되는 경우가 포함됩니다. 비동기식 신호는 통상 다른 프로세스에게 전달됩니다.

모든 신호는 둘 중 하나의 처리기에 의해 처리됩니다.

  • 디폴트 신호 처리기
  • 사용자 정의 신호 처리기

모든 신호마다 커널이 실행시키는 디폴트 신호 처리기가 있습니다. 이 디폴트 처리기는 신호를 처리하기 위하여 호출되는 사용자 정의 처리기에 의해 대체될 수 있습니다.

단일 스레드 프로그램의 신호 처리는 간단합니다. 신호는 항상 프로세스에게 전달됩니다. 그러나 프로세스가 여러 스레드를 가지고 있는 다중 스레드 프로그램에서의 신호 처리는 복잡합니다. 어느 스레드에게 신호를 전달해야 하는지 다음과 같은 선택을 해야합니다.

  • 신호가 적용될 스레드에게 전달합니다.
  • 모든 스레드에게 전달합니다.
  • 몇몇 스레드에가만 선택적으로 전달합니다.
  • 특정 스레드가 모든 신호를 전달받도록 지정합니다.

이처럼 신호를 전달하는 방법은 신호의 유형에 따라 다릅니다.

취소(Cancellation)

스레드 취소(thread cancellation)은 스레드가 끝나기 저네 그것을 강제 종료 시키는 작업입니다. 여러 스레드들이 DB를 병렬로 검색하고 있다가 그 중 한 스레드가 결과를 찾았다면 나머지 스레들은 취소되어도 되는 경우입니다.

이처럼 취소되어야 할 스레드를 목적 스레드(target thread)라고 부릅니다. 목적 스레드의 취소는 다음과 같은 두 가지 방식으로 발생할 수 있습니다.

  • 비동기식 취소 : 한 스레드가 즉시 목적 스레드를 강제 종료시킨다.
  • 지연취소 : 목적 스레드가 주기적으로 자신이 강제 종료 되어야하는지 점검합니다.

요약

스레드는 프로세스 안의 제어 흐름입니다. 다중 스레드 프로세스는 같은 주소 공간 안에 여러 개의 서로 다른 제어 흐름을 가지고 있습니다. 다중 스레딩의 장점은 사용자에 대한 향상된 응답성, 프로세스 내의 자원 공유, 경제성 및 더 효율적인 다중 처리 코어의 이용과 같은 규모 적응성 요소 등입니다.

사용자 수준 스레드는 프로그래머에게는 보이나, 커널은 알 수가 없는 스레드입니다. 커널 수준 스레드는 운영체제 커널에 의해서 지원되며 관리됩니다. 일반적으로, 커널의 개입을 필요로 하지 않기 때문에 사용자 수준 스레드는 커널 수준 스레드보다 빠르게 생성되고, 빠르게 관리됩니다. 사용자와 커널 스레드와 관련하여 세 가지의 모델이 있는데, 다대일 모델은 여러 개의 사용자 스레드를 하나의 커널 스레드로 관리합니다. 일대일 모델은 각 사용자 스레드를 그에 대응하는 커널 스레드로 관리합니다. 다대다 모델은 많은 사용자 스레드를 그보다 적은 수 또는 같은 수의 커널 스레드로 관리합니다.

다중 스레드 프로그램은 프로그램에게 fork()와 exec() 시스템 호출의 의미 등과 같은 많은 새로운 숙제를 안겨줍니다. 도 다른 쟁점들로는 스레드 취소, 신호 처리, 스레드 국지 저장소 등이 있습니다.


이상 공룡책 4장 스레드였습니다. ^_^

반응형
LIST

'OS > OS' 카테고리의 다른 글

공룡책 6장 프로세스 동기화  (0) 2019.11.07
공룡책 5장 CPU 스케줄링  (2) 2019.11.06
공룡책 3장 프로세스  (0) 2019.11.02
하이버네이트(Hibernate)란?  (0) 2019.06.30
멀티스레딩이란?  (0) 2019.06.17