C++ STL: 7장 - STL과 멀티스레딩 활용
2025. 2. 26. 18:16ㆍ프로그래밍 언어/C++ STL
7.1 C++과 멀티스레딩 개요
C++11부터 표준 라이브러리에서 멀티스레딩 지원이 강화되었습니다. STL은 멀티스레딩을 직접적으로 지원하지는 않지만, C++ 표준 스레딩 라이브러리(<thread>, <mutex>, <condition_variable> 등)와 함께 사용하여 멀티스레딩 환경에서 STL 컨테이너와 알고리즘을 효과적으로 활용할 수 있습니다.
7.2 STL 컨테이너와 멀티스레딩
7.2.1 컨테이너의 스레드 안전성
- STL 컨테이너는 기본적으로 스레드 안전하지 않습니다.
- 단일 스레드에서 사용하거나, 여러 스레드가 컨테이너에 읽기만 수행할 때는 안전합니다.
- 쓰기 작업이 포함된 경우, 동기화(std::mutex)가 필요합니다.
7.2.2 컨테이너 동기화 기법
- 뮤텍스 사용: 스레드 간 동기화를 위해 std::mutex를 사용하여 데이터 접근을 제어합니다.
예제:
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
std::vector<int> data;
std::mutex data_mutex;
void add_data(int value) {
std::lock_guard<std::mutex> lock(data_mutex);
data.push_back(value);
}
int main() {
std::thread t1(add_data, 1);
std::thread t2(add_data, 2);
t1.join();
t2.join();
for (int n : data) {
std::cout << n << " ";
}
return 0;
}
7.2.3 멀티스레딩에 적합한 컨테이너 선택
- 읽기 중심 작업:
- 추천: std::vector, std::deque, std::array (읽기 작업은 스레드 안전).
- 동시 쓰기 작업:
- 동기화를 직접 구현하거나, 멀티스레딩을 지원하는 컨테이너(예: tbb::concurrent_vector)를 사용하는 것이 좋습니다.
Note: Intel TBB와 Boost 라이브러리는 멀티스레드 지원을 강화하지만, STL의 일부가 아닙니다.
7.3 STL 알고리즘과 멀티스레딩
7.3.1 병렬 알고리즘
C++17에서는 <execution> 헤더를 통해 STL 알고리즘에 병렬 실행 정책이 도입되었습니다. 이를 사용하면 STL 알고리즘을 멀티스레드로 병렬화할 수 있습니다.
- 실행 정책:
- std::execution::seq: 순차 실행 (기본값).
- std::execution::par: 병렬 실행.
- std::execution::par_unseq: 병렬 + 비순차 실행 (가장 빠름).
예제:
#include <iostream>
#include <vector>
#include <algorithm>
#include <execution>
int main() {
std::vector<int> vec = {5, 3, 8, 1, 4};
std::sort(std::execution::par, vec.begin(), vec.end());
for (int n : vec) {
std::cout << n << " ";
}
return 0;
}
7.3.2 병렬 알고리즘 사용 시 주의사항
- 데이터 크기: 병렬화를 사용하는 경우, 데이터 크기가 충분히 크지 않으면 오히려 성능이 저하될 수 있습니다.
- 데이터 동기화: 공유 자원에 접근하는 경우 동기화가 필요합니다.
- 알고리즘 지원 여부: 모든 STL 알고리즘이 병렬 실행을 지원하지는 않습니다.
7.4 락 없는 프로그래밍
7.4.1 락 없는 자료구조
- 멀티스레딩 환경에서 락을 사용하지 않고 데이터를 안전하게 처리하기 위한 기법입니다.
- C++ 표준에는 락 없는 컨테이너가 포함되어 있지 않으나, 외부 라이브러리(예: Intel TBB, Boost)에서 지원합니다.
7.4.2 원자적 연산
- std::atomic을 사용하면 락 없이 스레드 간 데이터를 안전하게 읽고 쓸 수 있습니다.
예제:
#include <iostream>
#include <atomic>
#include <thread>
std::atomic<int> counter(0);
void increment() {
for (int i = 0; i < 1000; ++i) {
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << "\n";
return 0;
}
7.5 멀티스레딩 활용 사례
7.5.1 데이터 처리 병렬화
- 상황: 대규모 데이터 정렬 또는 변환.
- 해결책: std::sort와 같은 알고리즘에 std::execution::par를 사용하여 병렬화.
7.5.2 스레드 풀 구현
- 상황: 여러 작업을 효율적으로 관리.
- 해결책: 사용자 정의 스레드 풀 구현.
예제:
#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t threads);
~ThreadPool();
template <class F>
void enqueue(F&& f);
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
ThreadPool::ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers)
worker.join();
}
template <class F>
void ThreadPool::enqueue(F&& f) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
int main() {
ThreadPool pool(4);
for (int i = 0; i < 8; ++i) {
pool.enqueue([i] {
std::cout << "Task " << i << " is running.\n";
});
}
return 0;
}
Note: 위 예제는 간단한 스레드 풀 구현을 보여줍니다. 실제 사용 시에는 예외 처리, 작업 우선순위, 최적화 등이 필요할 수 있습니다.
결론
STL과 C++ 멀티스레딩 기능을 결합하면 강력한 병렬 프로그래밍이 가능합니다. STL 컨테이너와 알고리즘을 적절히 동기화하고, 병렬 알고리즘과 원자적 연산을 활용하면 안전하고 효율적인 멀티스레드 애플리케이션을 작성할 수 있습니다.
'프로그래밍 언어 > C++ STL' 카테고리의 다른 글
C++ STL: 9장 - STL 내부 구현 심화 (0) | 2025.02.26 |
---|---|
C++ STL: 8장 - STL과 고급 템플릿 기법 (0) | 2025.02.26 |
C++ STL: 6장 - STL 컨테이너 성능 비교와 활용 사례 (0) | 2025.02.26 |
C++ STL: 5장 - STL과 메모리 관리 (0) | 2025.02.26 |
C++ STL: 4장 - STL 알고리즘 (0) | 2025.02.25 |