C++에서 지원하지 않아 OS마다 구현 방법이 달랐다.
OS Lib를 가져다 써야하던 Thread 기능이 생겼다. (C++11)
표준 c++ 쓰레드
이동 가능
복사 불가능
thread() noexcept;
template<class Function, class... Args>
explicit thread(Function&& f, Args&&... args);
std::thread emptyThread;
std::thread printThread(PrintMsg, 10); // void PrintMsg(int count);
thread(thread&& other) noexcept;
thread(const thread&) = delete;
std::thread printThread(PrintMsg, 10);
std::thread movedThread(std::move(printThread)); // printThread는 더이상 쓰레드가 아님
std::thread copiedThread = movedThread; // ERROR ! 복사 생성자 없음
Thread의 고유 ID를 가져온다.
ID가 꼭 Int형으로 정의된 것이 아니기 때문에 ID 타입을 사용해야한다.
OS별로 ID를 다르게 관리하기 때문이다.
std::thread::id childThreadID = thread.get_id();
int main()
{
std::thread thread(PrintMsg, "msg from a chil thread");
thread.join();
}
join된 쓰레드가 끝날때까지 기다린다.
int main()
{
std::thread thread(PrintMsg, "msg from a chil thread");
thread.detach();
if (thread.joinable()) // join 가능한지 확인
{
thread.join(); // detach된것은 join 불가
}
}
메인 쓰레드와 무관하게 독립적으로 실행되도록 떼어낸다
현재 thread 실행을 멈춘다.
std::this_thread::sleep_for(std::chrono::seconds(3));
다른 쓰레드가 갈수 있도록 양보한다.
std::this_thread::yield();
공유 자원을 잠근다.
lock 되어 있으면 다른 thread가 접근 못한다.
void PrintMsg(const std::string& message)
{
static std::mutex m;
m.lock();
std::cout << message << std::endl;
m.unLock();
}
int main()
{
std::thread thread(PrintMsg, "Message from a child thread.");
PrintMsg("Msg from a main thread.");
thread.join();
return 0;
}
재귀함수를 사용하여 같은 쓰레드에서 또 lock을 시도하려고 할 경우 deadlock 걸릴 수 있다.
이럴 경우 사용
c++ 17부터 지원.
일반 lock 보다는 scoped_lock을 사용하자 !
여러 mutex를 동시에 걸 수 있다.
{ }를 지정해서 최소 범위에만 걸도록 하자.
{
static std::mutex m;
{
std::scoped_lock<std::mutex> lock(m);
std::cout << message << std::endl;
}
}
이벤트 개체
신호를 받을 때까지 현재 쓰레드의 실행을 멈춤.
template<class Predicate>
void wait(std::unique_lock<std::mutex& lock, Predicate pred);
while (!pred())
{
wait(lock);
}
두 번째 변수 pred가 false일때만 lock을 걸게 할 수 있다.
잘못 깨어날 위험을 줄인다.
#include <iostream>
#include <mutex>
#include <queue>
static std::mutex sQueueLock;
static std::condition_variable sEvent;
static std::queue<int> sQueue;
void Consume()
{
while (true)
{
int val;
{
std::unique_lock<std::mutex> lock(sQueueLock);
sEvent.wati(lock, [] { return !sQueue.empty(); });
val = sQueue.front();
sQueue.pop();
}
std::cout << val << std::endl;
}
}
void Produce()
{
std::unique_lock<std::mutex> lock<sQueueLock);
sQueue.push(1);
sEvent.notify_one();
}
int main()
{
std::thread producer(Produce);
std::thread consumer(Consue);
consumer.join();
producer.join()
return 0;
}