리눅스 쓰레드(linux thread) 처리, 커널 레벨(kernal level) 쓰레드와 유저 레벨(user level) 쓰레드
우분투 환경에서 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)에서 동작 중인지 나타냄
- 프로세스의 스레드들을 몇몇 프로세서에 한꺼번에 디스패치 할 수 있기 때문에 멀티프로세서 환경에서 매우 빠르게 동작한다.
- 커널이 각 스레드를 개별적으로 관리할 수 있다.
- 다른 스레드가 입출력 작업이 다 끝날 때까지 다른 스레드를 사용해 다른 작업을 진행할 수 있다.
- 스케줄링과 동기화를 위해 커널을 호출하는데 이는 비용이 상당하다(오래걸린다).
- 사용자가 프로그래밍할 때 구현하기 어려받.
- 자원을 더 많이 소비하는 경향이 있다.
- 운영체제에서 스레드를 지원할 필요가 없다.
- 스케줄링 결정이나 동기화를 위해 커놀을 호출하지 않기 때문에 인터럽트가 발생할 때 커널 레벨 스레드보다 오버헤드가 적다(컨텍스트 스위칭).
- 커널이 멀티스레드 프로세스를 한 스레드로 간주한다.
- 시스템 전반에 걸친 스케줄링 우선순위를 지원하지 않는다.
- 프로세스에 속한 스레드 중 I/O 작업등에 의해 하나라도 블록이 걸린다면 전체 스레드가 블록된다.
따라서 NPTL은 커널 스레드라고 말할 수 있으며 랩핑된 thread 클래스 또한 커널이 스케줄링하기 때문에
스레드를 생성할 때 각각의 스레드는 다른 프로세서에 할당되는 것이다.