안녕하세요. 우당탕탕 개발일지 입니다. 중간 D-3 레츠고
출제) 프로세스와 스레드 차이점
: 프로세스는 운영체제가 응용프로그램으로 적재하는 단위 & 스레드는 운영체제의 실행단위.
예상) 환경 컨텍스트, 실행 컨텍스트 차이
CH 4-1 프로세스의 문제점.
( 운영체제 실행단위 : 스레드 / 멀티 테스킹의 기본단위 : 프로세스)
프로세스를 실행단위로 하는 멀티 테스킹의 문제점 : 커널에 많은 시간적, 공간적 부담 ▶ 시스템 전체 속도 저하
1. 프로세스 생성의 큰 오버헤드
2. 프로세스 컨텍스트 스위칭의 큰 오버헤드
3. 프로세스 사이의 통신이 어려움.
**오버헤드 : 추가로 드는 부담, 비용, 시간
** 컨텍스트 스위칭 : cpu가 다른 프로세스로 바꿔서 실행할 떄, 이전 상태 저장 + 새 상태 불러오기
프로세스가 다른 프로세스의 메모리에 접근 불가
→ 공유 메모리나 소켓 등등 이용 : 코딩이 어렵고 실행 속도가 느리고 운영체제 호환성이 부족함.
CH 4-2 스레드 개념
멀티 태스킹의 문제점 : 커널에 많은 시간, 공간 부담 ⇒ 시스템 전체 속도 저하
해결방안 ) 스레드 출현 4가지 이유 : 새로운 실행단위
- 프로세스보다 크기가 작음.
- 프로세스보다 생성 및 소멸이 빠름
- 컨텍스트 스위칭이 빠름
- 통신이 쉬운, 실행 단위 필요.
스레드는 운영체제에게 실행단위이고 스테줄링 단위
- 스레드는 코드, 데이터, 립 , 스택을 가진 실체
- 스레드 마다 스레드 정보를 저장하는 구조체 TCB (Thread Control Block)있음.
프로세스는 스레드들의 컨테이너
프로세스 =하나의 아파트
스레드 = 안에 사는 사람들
공유 자원 = 수도, 전기 , 엘리베이터 등등
컨테이너 = 아파트 단지
프로세스는 반드시 하나 이상의 스레드로 구성.

PCB(Process Control Block) : 프로세스 전체의 정보를 관리하는 자료구조.
TCB(Thread Control Block) : 프로세스 안에서 각각의 스레드 정보를 관리하는 자료구조.
프로세스는 스레드의 공유 공간(환경) 제공
모든 스레드는 프로세스의 코드, 데이터, 힙 공유 + 스택 공간을 나누어 사용.
공유할때 한번에 공유하면 병목 현상 발생 ⚠️ → 해결) 동기화
스레드가 실행할 작업은 함수로 작성
즉. 스택 영역은 공유하지 않고 각 스레드 마다 자신의 스택을 가짐.
스레드의 생명과 프로세스의 생명 ⭐ ⭐ ⭐
(스레드의 종료와 프로세스 종료를 분리해서 생각하기! )
스레드 종료
- 스레드로 만든 함수 종료 →스레드 종료 (함수내 지역 변수, 스택이 사라짐)
- 스레드 종료 → 스레드 관련 정보 모두 제거됨 ( TCB제거)
프로세스 종료
- 프로세스에 속한 모든 스레드 종료 [더 이상 종료할 프로세스가 없을때] → 프로세스 종료
- 프로세스 종료 ( TCB제거, 4계층 메모리 해제 , PCB 삭제) →스레드 종료
#include <pthread.h> // pthread 라이브러리를 사용하기 위해 필요한 헤더 파일
#include <stdio.h>
#include <stdlib.h>
void* calcThread(void *param); // 스레드로 작동할 코드(함수)
int sum = 0; // main 스레드와 calcThread가 공유하는 전역 변수
int main() {
pthread_t tid; // 스레드의 id를 저장할 정수형 변수💡
pthread_attr_t attr; // 스레드 정보를 담을 구조체
pthread_attr_init(&attr); // 디폴트 값으로 attr 초기화
pthread_create(&tid, &attr, calcThread, "100"); // calcThread 스레드 생성 1️⃣
// 스레드가 생성된 수 커널에 의해 언젠가 스케줄되어 실행
pthread_join(tid, NULL); // tid 번호의 스레드 종료를 기다림
printf("calcThread 스레드가 종료하였습니다.\n");4️⃣
printf("sum = %d\n", sum);5️⃣
}
void* calcThread(void *param) { // param에 "100" 전달 받음💡
printf("calcThread 스레드가 실행을 시작합니다.\n");2️⃣
int to = atoi(param); // to = 100
int i;
for(i=1; i<=to; i++) // 1에서 to까지 합 계산
sum += i; // 전역 변수 sum에 저장3️⃣💡
}
$ gcc -o makethread makethread.c -lpthread
$ ./makethread
calcThread 스레드가 실행을 시작합니다.
calcThread 스레드가 종료하였습니다.
sum = 5050
총 스레드 수 2개 : 1) 메인 스레드 2) 새로 만든 스레드
- 프로세스 시작 : 메인 스레드 자동 생성
- pthread_create 호출 : 새 스레드 생성


→ 각 프로세스 안에 스레드가 각각 있으니까 오버헤드가 덜 발생. (스레드 사용의 목적!)
함수는 다른 함수에 의해 호출되어 실행되지만, 스레드 함수의 코드는 CPU가 바로 실행하도록 커널에 의해 제어됨
→ TCB는 커널에 의해 생성되고 관리가 됨!!.
멀티 스레딩
*동시성 : 3개의 스레드가 1개의 CPU에 의해 동시 실행.

* 병렬성 : 3개의 스레드가 3개의 cpu에 의해 동시 실행.

CH 4-3 스레드 주소 공간과 컨텍스트
스레드 주소 공간 : 스레드가 실행 중에 사용하는 메모리 공간.
스레드 주소 공간은 프로세스 주소 공간 내에 존재한다.

🦄사적 공간 (스택, TLS) vs 👻공유 공간 (코드, 데이터 공간, 힙영역)
<사용자 공간 >
스레드 코드영역 👻 : 함수
스레드 데이터 영역 👻 : 1) 전역 변수들 2) 개별 스레드의 전용 변수 공간. (TLS)
스레드 힙 👻 : 위에서 아래로 쌓임.
스레드 (사용자) 스택 🦄 : 아래에서 위로 쌓임 | 스레드가 생성될때 사용자 스택할당. & 종료시 반환.
<커널 공간 >
스레드 (커널) 스택 🦄 :
- 스레드가 생성될때 커널 공간에 스레드 마다 스택할당. & 종료시 반환
- 스레드가 시스템 호출로 커널에 진입할 때, 커널 스택 활용.
※ 스레드가 생성될때 마다 모든 스레드에 동일한 크기의 공간 할당.
static __thread int sum = 5;
TLS ( Thread Local Storage) : 스레드마다 안전하게 다루고자 하는 데이터를 저장하기 위한 별도의 영역
- 대체로 힙이나 스택 에 할당. 언어마다 운영체제마다 할당 방법이나 위치가 다름.
- TLS ↔ 프로세스의 데이터 영역은 모든 스레드의 공용 공간임.
- 스레드 삭제할 떄 TLS도 같이 사라짐 ( 내 개인적인 의견으로는 그냥 지역 변수를 떠올리면 될것 같음 )
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void printsum(); // 모든 스레드에 의해 호출되는 함수
void* calcThread(void *param); // 스레드 코드(함수)
static __thread int tsum = 5; // 스레드 로컬 스토리지(TLS)에 tsum 변수 선언
int total = 0; // 프로세스의 전역 변수, 모든 스레드에 의해 공유
int main() {
char *p[2] = {"100", "200"};
int i;
pthread_t tid[2]; // 스레드의 id를 저장할 정수 배열
pthread_attr_t attr[2]; // 스레드 정보를 담을 구조체
// 2개의 스레드 생성
for(i=0; i<2; i++) {
pthread_attr_init(&attr[i]); // 구조체 초기화
pthread_create(&tid[i], &attr[i], calcThread, p[i]); // 스레드 생성
printf("calcThread 스레드가 생성되었습니다.\n");
}
// 2개 스레드의 종료를 기다린 후에 total 값 출력
for(i=0; i<2; i++) {
pthread_join(tid[i], NULL); // 스레드 tid[i]의 종료대기
printf("calcThread 스레드가 종료하였습니다.\n");
}
printf("total = %d\n", total); // 2개 스레드의 합이 누적된 total 출력
return 0;
}
void* calcThread(void *param) { // 스레드 코드
printf("스레드 생성 초기 tsum = %d\n", tsum); // TLS 변수 tsum의 초기값 출력
int i, sum = 0; // 지역 변수
for(i=1; i<= atoi(param); i++) sum += i; // 1~param까지 더하기
tsum = sum; // TLS 변수 tsum에 합 저장
printsum();
total+=sum; // 전역 변수 total에 합 누적
}
void printsum() { // 모든 스레드가 호출할 수 있는 공유 함수
printf("계산 후 tsum = %d\n", tsum);
}
Q1 출력되는 순서대로 써보기
$ gcc -o mtTLS makethreadwithTLS.c –lpthread
$ ./mtTLS
calcThread 스레드가 생성되었습니다.
스레드 생성 초기 tsum = 5
calcThread 스레드가 생성되었습니다.
계산 후 tsum = 5050
스레드 생성 초기 tsum = 5
계산 후 tsum = 20100
calcThread 스레드가 종료하였습니다.
calcThread 스레드가 종료하였습니다.
total = 25150
$
Q2 TLS, 코드 , 데이터, 힙, 스택에 들어가는 거 그려보기 + 총 몇개의 스레드가 생성되는지 알아보기

총 스레드는 3개. tsum의 값 변화 위주로 보기
Q3 tsum을 어떤 변수라고 부르는가? 그리고 total 변수와의 차이점은 무엇인가?
A3. tsum은 TLS 변수로 불린다. tsum은 각 스레드의 TLS 영역에 스레드마다 생기고 스레드에 의해 사적으로 사용.
total은 프로세스의 전역변수로서 프로세스 전체에 하나만 생기고 프로세스에 속한 모든 스레드에 의해 공유
스레드 일생
스레드 상태는 TCB에 저장.

Ready : 스레드가 스케줄 되기를 기다리는 상태
Running : 스레드가 CPU에 의해 실행 중인 상태
Blocked : 스레드가 입출력을 요청하거나 sleep() 같은 시스템 호출로 인해 중단된 상태
Terminated : 스레드가 종료한 상태.
스레드 운영
1) 스레드 생성
자동으로 main스레드 & 시스템 호출
2) 스레드 종료
프로세스 종료 / 스레드 종료
3) 스레드 조인
스레드가 다른 스레드 종료할 때 까지 대기
( ex 부모가 자식 종료할때까지 대기 )

4) 스레드 양보
스레드가 자발적으로 yield()와 같은 함수 호출을 통해 스스로 실행을 중단하고 다른 스레드를 스케줄하도록 요청
스레드 컨텍스트 : 실행중인 cpu의 상태 정보
- TCB에 저장됨.
- 컨텍스트 정보 : PC,SP, 다른 레지스터 등등
- PC : 프로세스 코드 & SP : 프로세스 스택에 저장.

스레드 컨텍스트 스위칭
: 현재 실행중인 스레드 저장 - 새로운 스레드 실행 -이전에 실행하던 스레드 불러옴.
:스레드 스케줄링 후 ⇒ 실행중인 스레드를 중간 시키고 선택된 스레드에게 cpu 할당.
스레드 (컨텍스트) 스위칭 발생 경우
→ 상태 전이도를 생각하면서 4가지 경우 생각해보기⭐️⭐️⭐️
- 스레드 양보
- 시스템 호출 → wait() 이나 blocked() 상태
- 스레드 타임 슬라이드를 소진한 경우 (TTS)
- 인터럽트 I/O
스레드 스위칭이 이루어지는 위치 : 커널
1. 시스템 호출 중 : 커널 모드 (자발적)
2. 인터럽트 발생시 : 커널 모드 (강제적)
스레드 스위칭 과정
- 원본 TCB → 준비 리스트(Ready List) 또는 블록 리스트(Block List) 로 이동
- 인터럽스 TCB→ 준비 리스트에서 분리되어 실행(Running) 상태로 변경
컨텍스트 스위칭 오버헤드
: 컨텍스트 스위칭은 모두 cpu 작업이기 떄문에 컨텍스트 스위칭의 시간이 길거나 잦은 경우 발생.
| 동일 프로세스 내 스레드 스위칭 | CPU 레지스터 저장/복원, TCB 수정, 캐시 일부 변경 | 오버헤드 작음 |
| 다른 프로세스 간 스레드 스위칭 | PCB + TCB 교체, 페이지 테이블 교체, TLB 초기화, 캐시 전체 무효화 | 오버헤드 큼 |
TCB
= 스레드 엔터티 or 스케줄링 엔터티라고 불림
: 스레드를 실행 단위로 다루기 위해 스레드에 관한 정보를 담은 구조체

| 스레드 정보 | tid |
| state | |
| 컨텍스트 | PC |
| SP | |
| 다른 레지스터들 | |
| 스테줄링⭐️ | 우선순위 |
| CPU 사용시간 |
PCB와 TCB의 관계
PCB와 나머지 TCB들이 포인터(pointer)로 연결됨.
TCB와 TCB는 연결 리스트(linked list)로 되어 있음
→이유 : 스레드의 갯수가 가변적이고 삽입/삭제가 잦기 때문.

→ 누가 먼저 실행될지는 알수 없고 커널이 cpu 스케줄링 시 선택해서 실행됨.
준비 리스트 / 블록 리스트
- CPU를 기다리면 (Ready)→ 준비 리스트(Ready List)
- 입출력(I/O)을 기다리면 (Blocked , waiting)→ 블록 리스트(Blocked List)
CH 4-4 커널 레벨 스레드와 사용자 레벨 스레드 ( 출제 가능성 낮음)
스케줄링 주체에 따라 2종류의 스레드로 구분.
- 커널 레벨 스레드 : 커널에 의해 스케줄링
- 사용자 레벨 스레드 : 스레드 라이브러리에 의해 스케줄링
→ 프로세스당 하나의 커널 레벨 스레드(=메인 스레드 ) 자동 생성.
순수 커널 레벨 스레드 :운영체제 부팅 시 커널이 직접 생성한 스레드
- 커널 모드에서만 사용되는거고 사용자가 조정하는게 아님.
- ex) usb 같은거 연결할때, 마우스 클릭
| 사용자 레벨 스레드 | 커널 레벨 스레드 | |
| 스레드 스위칭 | 사용자모드에서 | 커널 모드에서 |
| 경향 | 잘 안씀 | 많이씀 |
| 컨텍스트 스위칭 속도 | 빠름 | 느림 |
| 병렬성 | 동시성 | 병렬성 |
CH 4-5 멀티 스레드 구현 ( 출제 가능성 낮음)
개발자가 멀티 스레드 구현 방법 3가지
- 1:1 (현재 사용)
- N:1
- N:M
1:1 (멀티코어 병렬 처리 완벽 지원.& 구현이 쉬움)
[사용자 공간] [커널 공간]
U-TCB1 ──────────────▶ K-TCB1 ─▶ CPU 코어1
U-TCB2 ──────────────▶ K-TCB2 ─▶ CPU 코어2
U-TCB3 ──────────────▶ K-TCB3 ─▶ CPU 코어3
N:1 병렬처리가 안되서 비효율적임.
[사용자 공간] [커널 공간]
U-TCB1 ─┐
U-TCB2 ├─▶ K-TCB1 ─▶ CPU 코어1
U-TCB3 ┘
M:N 구현이 복잡하고, 유지보수가 어려움
[사용자 공간] [커널 공간]
U-TCB1 ─┐
U-TCB2 ├─▶ K-TCB1 ─▶ CPU 코어1
U-TCB3 ┘
U-TCB4 ─▶ K-TCB2 ─▶ CPU 코어2
U-TCB5 ─▶ K-TCB3 ─▶ CPU 코어3
CH 4-6 멀티 스레딩에 관한 이슈 ( 출제 가능성 낮음)
4장 요약
- 프로세스는 스레드들의 공유 공간(컨테이너) : 모든 스레드의 주소 공간이 프로세스 주소 공간 내에 형성되고 공유
- 프로세스는 운영체제가 응용프로그램을 적재하는 단위이고, 스레드는 실행 단위
- PCB에 저장된 정보는 환경 컨텍스트, TCB에 저장된 정보는 실행 컨텍스트
- 다른 프로세스에 속한 스레드로의 스위칭보다 동일한 프로세스에 속한 스레드 스위칭 속도가 빠름
- 프로세스에 속한 모든 스레드가 종료할 때 프로세스 종료
멀티 스레딩 장점 )
- 높은 실행 성능 = 병렬 실행
- 사용자에 대한 우수한 응답성 : 사용자와의 입출력 가능
- 서버 프로그램의 우수한 응답성 : 동시에 많은 사용자들의 접근 가능.
- 효율성 높음 ) 스레드 >>> 프로세스
- 응용프로그램 구조의 단순화
- 작성이 쉽고 효율적인 통신
멀티 스레딩시 주의할 점)
- 여러 개의 스레드 중 한 스레드만 fork()를 호출하는 경우 : 새 프로세스에 한 스레드만 복사되어 ‘불완전한 복제’가 발생
- 멀티스레드 상태에서 하나의 exec()를 호출하는 것. : 현재 프로세스의 모든 스레드가 사라짐
- 스레드 사이의 동기화 문제 : 여러 스레드가 공유 데이터를 동시에 수정하면 데이터 손상 발생
(+ 규약) 멀티스레드 프로그램에서 fork()를 호출한 후, 자식 프로세스에서는 즉시 exec()만 호출해야 하며, 다른 함수 호출은 하지 말 것.
.
'[전공 CS] > [컴퓨터 구조론][운영체제]' 카테고리의 다른 글
| [운영체제] 6장 스레드 동기화 (0) | 2025.12.08 |
|---|---|
| [운영체제] 5장 CPU 스케줄링 (0) | 2025.12.07 |
| [운영체제] 03 프로세스와 프로세스 관리 (0) | 2025.10.20 |
| [운영체제] 02 컴퓨터 시스템과 운영체제 (0) | 2025.09.30 |
| [운영체제] 01 운영체제의 시작과 발전+ 전체 문제풀이 (0) | 2025.09.25 |