스레드
Thread
프로세스 내 실행 단위. 메모리를 공유하여 통신 가능. 동시성 프로그래밍의 기본 단위.
Thread
프로세스 내 실행 단위. 메모리를 공유하여 통신 가능. 동시성 프로그래밍의 기본 단위.
스레드(Thread)는 프로세스 내에서 실행되는 가장 작은 실행 단위입니다. 하나의 프로세스는 여러 스레드를 가질 수 있으며, 같은 프로세스 내의 스레드들은 메모리 공간(힙, 데이터 영역)을 공유합니다. 각 스레드는 독립적인 스택과 레지스터를 가지며, 이를 통해 병렬 실행이 가능합니다.
멀티스레딩의 주요 장점은 CPU 활용률 향상과 응답성 개선입니다. I/O 작업으로 대기하는 동안 다른 스레드가 CPU를 사용할 수 있고, UI 스레드와 작업 스레드를 분리하면 응답성 있는 애플리케이션을 만들 수 있습니다. 멀티코어 프로세서에서는 실제 병렬 처리로 성능이 향상됩니다.
스레드 간 메모리 공유는 양날의 검입니다. 효율적인 데이터 교환이 가능하지만, 동시 접근으로 인한 경쟁 조건(race condition)과 데이터 손상 위험이 있습니다. 이를 방지하기 위해 뮤텍스(mutex), 세마포어(semaphore), 락(lock) 등의 동기화 메커니즘을 사용합니다.
현대 프로그래밍에서는 스레드를 직접 관리하기보다 스레드 풀이나 고수준 추상화를 사용합니다. Java의 ExecutorService, Python의 ThreadPoolExecutor, Go의 고루틴과 채널 등이 그 예입니다. 이러한 추상화는 스레드 생성/소멸 비용을 줄이고 안전한 동시성 프로그래밍을 지원합니다.
// 다양한 언어의 스레드 예제
// Python - threading 모듈
import threading
import time
def worker(name):
print(f"스레드 {name} 시작")
time.sleep(2)
print(f"스레드 {name} 완료")
# 스레드 생성 및 실행
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
# 모든 스레드 완료 대기
for t in threads:
t.join()
print("모든 작업 완료")
// JavaScript - Web Workers (별도 파일)
// worker.js
self.onmessage = function(e) {
const result = heavyComputation(e.data);
self.postMessage(result);
};
// main.js
const worker = new Worker('worker.js');
worker.postMessage(data);
worker.onmessage = (e) => console.log('결과:', e.data);
// Rust - std::thread
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..5 {
println!("스레드에서: {}", i);
thread::sleep(Duration::from_millis(100));
}
});
handle.join().unwrap(); // 스레드 완료 대기
}
백엔드 개발자: "대용량 파일 처리 때문에 API 응답이 느려지고 있어요. 타임아웃이 자주 발생합니다."
기술 리더: "파일 처리를 별도 스레드나 워커로 분리하면 어떨까요? 요청은 즉시 응답하고 처리 결과는 비동기로 알려주는 방식으로요."
백엔드 개발자: "스레드 풀을 사용해서 동시 처리 수를 제한하면 좋겠네요."
기술 리더: "네, 그리고 처리 상태를 조회할 수 있는 API도 함께 만들어 주세요."
면접관: "스레드와 프로세스의 차이점을 설명해 주세요."
지원자: "프로세스는 독립적인 메모리 공간을 가지는 실행 단위이고, 스레드는 프로세스 내에서 메모리를 공유하는 실행 단위입니다. 스레드는 생성 비용이 적고 통신이 빠르지만, 동기화 문제가 발생할 수 있습니다."
면접관: "데드락은 어떤 상황에서 발생하나요?"
지원자: "두 개 이상의 스레드가 서로 상대방이 가진 락을 기다리며 무한 대기하는 상황입니다. 락 획득 순서를 일관되게 하거나, 타임아웃을 설정해서 예방할 수 있습니다."
리뷰어: "이 공유 변수에 여러 스레드가 동시에 접근하고 있는데, 동기화가 없네요."
작성자: "단순 읽기라서 괜찮을 거라 생각했는데, 문제가 될 수 있나요?"
리뷰어: "쓰기가 없으면 대부분 괜찮지만, 가시성 문제가 있을 수 있어요. volatile이나 Atomic 타입을 사용하거나, 락으로 감싸는 게 안전합니다."
작성자: "알겠습니다. AtomicInteger로 변경하고, 필요한 곳에 synchronized 블록도 추가하겠습니다."