Thread란?
스레드는 프로세스 내에서 실행되는 작업의 흐름이다. 하나의 프로세스는 하나 이상의 스레드를 갖고 있다.
스레드끼리는 코드, 힙, 데이터 영역은 공유하지만 스택 메모리는 따로 할당 받는다.
#include <iostream>
#include <thread>
void Hi()
{
cout << "HI" << endl;
}
int main()
{
std::thread t(Hi); //쓰레드 생성
if(t.joinable())
t.join();
}
t.hardware_concurrency() - 현재 시스템의 물리적 또는 논리적 CPU 코어 수 반환
t.get_id() - 스레드 객체의 고유 ID를 반환
t.detach() - 스레드를 독립적으로 실행되도록 함, 더 이상 join()으로 기다릴 수 없음
t.joinable() - 해당 스레드가 join()이 가능한 상태인지 확인
t.join() - 해당 스레드가 끝날때까지 대기
MultiThread란?
여러 개의 스레드를 동시에 실행 -> 즉 하나의 프로그램 안에서 여러 개의 작업을 동시에 수행한다.
성능 향상, 리소스 절약, 병렬 처리 등의 장점 도 있지만 동기화가 어렵고 Deadlock의 위험, context switching 비용 등의 단점도 있다.
동기화 방법
Atomic
atomic이란? 원자적이란 뜻으로 더 이상 쪼갤 수 없는 단위All or Nothing - 작업 중간에 다른 스레드가 끼어 들 수 없고 완전히 끝나거나, 시작 조차 하지 않은 상태만 존재
#include <iostream>
#include <thread>
atomic<int> sum = 0;
void Add()
{
for(int i 0; i<100; ++i)
sum++;
}
void Sub()
{
for(int i = 0; i<100; --i)
sum--;
}
int main()
{
std::thread t1(Add);
std::thread t2(Sub);
t1.join();
t2.join();
}
Lock 기초
mutex - mutual exclusion(상호 배제)
즉, 한 번에 오직 하나의 스레드만 자원에 접근할 수 있도록 하는 Lock이다.
#include <iostream>
#include <thread>
#include <mutex>
int sum = 0;
mutex m;
void Add()
{
for(int i 0; i<100; ++i)
{
m.lock();
sum++;
m.unlock();
}
}
void Sub()
{
for(int i 0; i<100; ++i)
{
m.lock();
sum--;
m.unlock();
}
}
int main()
{
std::thread t1(Add);
std::thread t2(Sub);
t1.join();
t2.join();
}
mutex를 자동으로 관리해주는 객체 lock_guard, unique_lock이 있다.
lock_guard의 특징
lock_guard는 생성 시 즉시 mutex를 잠그고, 소멸 시 자동으로 mutex를 풀어준다
스코프를 벗어나면 자동으로 unlock 된다.
std::lock_guard<<std::mutex> lockGuard(m);
unique_lock의 특징
lock_guard보다 더 기능이 많다.
lock 재잠금 및 해제가 가능하고, deferred와 cv등을 함께 사용할 수 있다.
std::unique_lock<std::mutex> uniqueLock(m, std::defer_lock);
uniqueLock.lock();
이렇게 사용할 경우 바로 잠기는 것이 아니라 잠기는 시점을 뒤로 미룰 수 있다.
'서버' 카테고리의 다른 글
std::future (0) | 2025.04.08 |
---|---|
조건 변수 Condition Variable (0) | 2025.04.08 |
DeadLock과 Lock구현 (0) | 2025.04.07 |