라봉이의 개발 블로그

리눅스 쓰레드(linux thread) 처리, 커널 레벨(kernal level) 쓰레드와 유저 레벨(user level) 쓰레드 본문

컴퓨터 사이언스/개인 연구

리눅스 쓰레드(linux thread) 처리, 커널 레벨(kernal level) 쓰레드와 유저 레벨(user level) 쓰레드

Labhong 2018. 4. 30. 20:59
반응형

우분투 환경에서 C++을 공부하는 와중에 Thread에 대해 연습해보다가 Thread에는 커널 레벨과 유저 레벨이 존재한다고 들었다. 그렇다면 C++ thread 클래스(pthread를 랩핑한)는 어떤 종류인지 찾아보고 싶었다.

또한 Thread들이 과연 각 Thread마다 물리적인 다른 CPU에 각각 할당이 될까?? 라는 궁금함에 자료조사를 해보았다.


그러기 위해서는 ubuntu에서 스레드 당 정말 각각의 CPU에 할당 되는 지를 직접 보고 싶었다.

과연 하나의 CPU에 할당이 되는 것인지, 스레드마다 각각 다른 CPU에 할당되는 지 눈으로 직접 보고싶었기에 조사를 해보았다.


먼저 C++ 코드를 작성하였다. 


#include <iostream>
#include <thread>
#include <queue>

using namespace std;

void helloWorld() {
  for(;;){}
}

int main() {
  thread t1(helloWorld);
  thread t1(helloWorld);

  t1.join();
  t2.join();

  return 0;
}


스레드를 두 개 만들어서 메인 스레드까지 총 3개가 생성되고 메인 스레드는 만들어진 두 개의 스레드가 끝나길 기다리고 있다.

하지만 무한루프이기 때문에 3개의 스레드는 CPU에 계속 할당되어 있고 우리가 모니터링할 때까지 계속 살아있을 것이다.


이제 각각의 스레드가 어떤 CPU에 할당되는 지 알아볼 차례이다.


먼저 PID(process id)를 알아야한다.

ps -ef | grep <프로그램 이름>

로 먼저 프로세스 아이디를 확인한 후

ps -T -p <pid>

로 스레드가 몇개 있는 지 확인 후

ps -mo pid,tid,%cpu,psr -p <pid>

로 pid, tid, %cpu, psr을 확인할 수 있다. 위의 단어들은 다음을 의미한다. 


  • pid: 프로세스 아이디
  • tid: 스레드 아이디
  • %cpu: cpu 사용률
  • psr: 어느 processor(CPU)에서 동작 중인지 나타냄
다음 사진으로 결과를 알 수 있다!!!



다음과 같이 각각의 스레드는 다른 7, 1, 2번 프로세서를 할당하는 것을 알 수 있다. (실행환경: ubuntu 16.04, 4 CPU, 8 Processor)

또한 조사를 해보니 Thread에는 커널 레벨, 유저 레벨의 스레드가 존재한다고 했다.

커널 레벨
  설명
커널 영역에서 스레드 연산을 수행한다. 
- 커널이 스레드를 관리하기 때문에 커널에 종속적이다.

   장점
  • 프로세스의 스레드들을 몇몇 프로세서에 한꺼번에 디스패치 할 수 있기 때문에 멀티프로세서 환경에서 매우 빠르게 동작한다. 
  • 커널이 각 스레드를 개별적으로 관리할 수 있다.
  • 다른 스레드가 입출력 작업이 다 끝날 때까지 다른 스레드를 사용해 다른 작업을 진행할 수 있다.
  단점
  • 스케줄링과 동기화를 위해 커널을 호출하는데 이는 비용이 상당하다(오래걸린다).
  • 사용자가 프로그래밍할 때 구현하기 어려받.
  • 자원을 더 많이 소비하는 경향이 있다.

유저 레벨
  설명
- 사용자 영역에서 스레드 연산을 수행한다. 
- 사용자 영역에서 스레드 연산을 수행하기 때문에 운영체제에 투명하다. 이는 운영체제가 각 스레드가 아닌 멀티스레드를 포함하는 프로세스 한 단위를 대상으로 프로세서를 할당한다는 의미이다.

  장점
  • 운영체제에서 스레드를 지원할 필요가 없다.
  • 스케줄링 결정이나 동기화를 위해 커놀을 호출하지 않기 때문에 인터럽트가 발생할 때 커널 레벨 스레드보다 오버헤드가 적다(컨텍스트 스위칭).
  단점
  • 커널이 멀티스레드 프로세스를 한 스레드로 간주한다. 
  • 시스템 전반에 걸친 스케줄링 우선순위를 지원하지 않는다.
  • 프로세스에 속한 스레드 중 I/O 작업등에 의해 하나라도 블록이 걸린다면 전체 스레드가 블록된다.

유저 레벨 스레드는 실행되고 있는 프로세스가 스레드를 관리하는 것이다.
커널 레벨 스레드는 OS가 관리한다. 반면에 유저 레벨 스레드는 유저(라이브러리 만든 사람)에 의해 관리되고 따라서 OS는 단일의 유저 레벨 스레드로 인식한다(실행중인 스레드).

따라서 단순 유저 레벨 스레드를 사용하는 경우 멀티프로세서의 장점을 갖지 못한다.
어차피 하나의 프로세스는 여러개의 스레드를 갖는다하여도 단일 프로세서에서 작동하기 때문이다.

그렇다면 C++에서 제공하는 thread 라이브러리는 유저 레벨인지 커널 레벨인지 궁금했다.
리눅스는 커널 v2.6 이상부터 NPTL로 구현이 되어 있다. NPTL은 1대1 스레드 라이브러리이며 그것은 사용자가 만든 스레드(pthread_create)가 스케줄링 단위가 된다.


따라서 NPTL커널 스레드라고 말할 수 있으며 랩핑된 thread 클래스 또한 커널이 스케줄링하기 때문에

스레드를 생성할 때 각각의 스레드는 다른 프로세서에 할당되는 것이다.

반응형
Comments