[C++] 쓰레딩(Threading) 라이브러리
카테고리: Cpp
이 글은 C++의 쓰레딩(Threading) 라이브러리를 공부하고 정리한 글입니다.
쓰레딩 라이브러리는 os마다 다르게 구현했던 멀티쓰레딩을 통합시킨 라이브러리이다.
쓰레딩 라이브러리
- 표준 C++ 쓰레드
- os마다 다르게 구현했던 멀티쓰레딩을 통합시킨 라이브러리
- 이동(move) 가능
-
복사 불가능
std::thread 생성자
thread() noexcept; template<class Function, class... Args> explicit thread(Function&& f, Args&&... args); thread(thread&& other) noexcept;
- 새 쓰레드 개체를 만든다
std::thread emptyThread; std::thread printThread(PringMessage, 10); // void PrintMessage(int count); std::thread movedThread(std::move(printThread)); // OK. printThread는 더 이상 쓰레드가 아님
std::thread::join()
void join();
- 쓰레드 개체가 끝날 때까지 현재 쓰레드를 멈춰 놓는다
- 이 함수를 호출한 후 쓰레드 개체를 안전하게 소멸시킬 수 있음
std::thread thread(PrintMessage); // void PrintMessage() {}; thread.join();
std::thread::get_id()
std::thread::id get_id() const noexcept;
- 쓰레드 ID를 반환한다
std::thread thread(PrintMessage); // void PrintMessage() {}; std::thread::id threadID = thread.get_id();
std::thread::detach()
void detach();
- 쓰레드 개체에서 쓰레드를 떼어 낸다
- 떼어진 쓰레드는 메인 쓰레드와 무관하게 독립적으로 실행됨
std::thread thread(PrintMessage); // void PrintMessage() {}; thread.detach();
std::thread::joinable()
bool joinable() const noexcept;
- 쓰레드가 실행 중인 활성 쓰레드인지 아닌지 확인한다
std::thread thread(PrintMessage); // void PrintMessage() {}; if(therad.joinable()) { // ... }
std::ref()
template<class T> std::reference_wrapper<T> ref(T& t) noexcept;
- T의 참조를 내포한 reference_wrapper 개체를 반환한다
-
헤더에 정의돼 있음 -
를 인클루드하면, 을 인클루드할 필요 없음
-
// void Sum(const std::vector<int>& list, int& result); std::thread thread(Sum, list, std::ref(result));
std::this_thread::sleep_for()
template<class Rep, class Period> void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration);
- 최소 sleep_duration만큼의 시간 동안 현재 쓰레드의 실행을 멈춘다
std::this_thread::sleep_for(std::chrono::seconds(1));
std::this_thread::yield()
void yield() noexcept;
- sleep과 비슷하나, sleep이 쓰레드를 일시 정지 상태로 바꾸는 반면, yiled는 계속 실행 대기 상태
- sleep_for(std::chrono::seconds(0)) 대신 yield()를 사용하는 것이 좋다
- sleep같은 경우 쓰레드를 멈추고 다시 가동하는 순간에 오버헤드가 생기고 느려진다
std::this_thread::sleep_for(std::chrono::seconds(1));
std::mutex 생성자
1. constexpr mutex() noexcept; 2. mutex(const mutex&) = delete;
- 뮤텍스를 만든다
- 복사 생성자는 delete 처리됨
std::mutex mutex;
std::mutex::lock()
void lock();
- 뮤텍스를 잠근다
- 동일한 쓰레드에서 두 번 잠그면 데드락(deadlock) 발생
- 꼭 그렇게 해야 된다면, std::recursive_mutex를 사용
std::mutex mutex; mutex.lock();
std::mutex::unlock()
void unlock();
- 뮤텍스 잠금을 푼다
- 현재 쓰레드에서 잠긴 적이 없을 때의 행동은 정의되지 않음
std::mutex mutex; mutex.lock(); mutex.unlock();
std::scoped_lock()
template<class... MutexTypes> class scoped_lock;
- 매개변수로 전달된 뮤텍스(들)을 내포하는 개체를 만듬
- 개체 생성시에 뮤텍스를 잠그고 범위(scope)를 벗어나 소멸될 때 품
- 데드락을 방지
- C++14의 경우, std::lock_guard를 사용할 수 있으나 이 때는 뮤텍스를 하나만 전달 가능
std::scoped_lock<std::mutex> lock(mutex); std::scoped_lock<std::mutex, std::mutex> locks(mutex1, mutex2); std::scoped_lock<std::mutex, std::mutex, std::mutex> locks(mutex1, mutex2, mutex3);
std::condition_variable()
- 이벤트 개체
- 신호를 받을 때까지 현재 쓰레드의 실행을 멈춤
- notify_one(), notify_all()
- 멈춰 놓은 쓰레드 하나 또는 전부를 다시 실행시킴
- wait(), wait_for(), wait_until()
- 조건 변수의 조건을 충족시킬때까지 또는 일정 시간 동안 현재 쓰레드의 실행을 멈춤
std::unique_lock
을 사용해야 함
std::unique_lock
- 기본적으로 scoped lock
- 생성시에 lock을 잠그지 않을 수도 있음(두 번째 매개변수로
std::defer_lock
을 전달할 것) std::recursive_mutex
와 함께 써서 재귀적으로 잠글 수 있음- 조건 변수에 쓸 수 있는 유일한 lock
std::scoped_lock<std::mutex> lock(mutex); std::scoped_lock<std::mutex, std::mutex> locks(mutex1, mutex2); std::scoped_lock<std::mutex, std::mutex, std::mutex> locks(mutex1, mutex2, mutex3);
std::condition_variable::wait()
1. void wait(std::unique_lock<std::mutex>& lock); 2. template<class Predicate> 2. void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
- 현재 쓰레드 뮤텍스의 잠금을 풀고 notify_one() 또는 notify_all()을 기다린다
- 깨어나면, 뮤텍스를 다시 잠근다
-
ntiofy_xxx()가 wait()보다 먼저 호출되면, 해당 쓰레드는 영원히 기다린다
- 2번째 경우
- 아래와 같음
while (!pred()) { wait(lock); }
- 두가지 용도로 사용
- 잘못 깨어날 위험을 줄임
- pred()는 잠긴 두 쓰레드 모두에서 접근할 수 있는 bool 변수의 역할을 함
- lock만 쓰는 것은 충분하지 않음
sEvent.wait(lock);
- 조건변수가 신호(signal)을 받기 전에 대기 상태에 들어가는 것을 보장할 수 없다면 항상 bool 조건과 lock을 같이 사용할 것
sEvent.wait(lock, [] { return !sQueue.empty(); });
참조
💻 열심히 공부해서 작성 중이니 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 알려주시면 감사하겠습니다! 😸
댓글 남기기