#include <thread>
void PrintMessage(const std::string& message)
{
std::cout << message << std::endl;
}
int main()
{
std::thread thread(PrintMessage, "message from a child thread.");
PrintMessage("Message from a main thread");
thread.join();
return 0;
}
출력이 섞인다...
해결책) 공유자원 잠그기
##include <mutex>
void PrintMessage(const std::string& message)
{
static std::mutex sMutex;
sMutex.lock();// lock, unlock을 순수 호출하는 것은 나쁜 아이디어...
std::cout << nessage << std::endl;
sMutex.unlock();
}
int main()
{
std::thread thread(PrintMessage, "message from a child thread.");
PrintMessage("Message from a main thread");
thread.join();
return 0;
}
constexpr mutex() noexcept;//뮤텍스를 만든다
mutex(const mutex&) = delete;//복사 생성자는 delete 처리됨.
std::mutex::lock()
std::mutex::unlock()
흔히 하는 실수
##include <mutex>
void PrintMessage(const std::string& message)
{
static std::mutex sMutex;
sMutex.lock();// lock, unlock을 순수 호출하는 것은 나쁜 아이디어...
std::cout << nessage << std::endl;
// 코드를 실수로 빼먹을 수 있다.
// unlock 코드가 있더라도 위의 코드에서 중간에 return 되면 unlock을 못함
//sMutex.unlock();
}
int main()
{
std::thread thread(PrintMessage, "message from a child thread.");
PrintMessage("Message from a main thread");
thread.join();
return 0;
}
void PrintMessage(const std::string& message)
{
static std::mutex sMutex;
std::scoped_lock<std::mutex> lock(sMutex);
std::cout << nessage << std::endl;
}
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);
Ex)
##include <mutex>
void PrintMessage(const std::string& message)
{
static std::mutex sMutex;
{
std::scoped_lock<std::mutex> lock(sMutex);
std::cout << "Message from thread ID " >> std::this_thread::get_id() << std::endl;
}
{
std::scoped_lock<std::mutex> lock(sMutex);
std::cout << message << std::endl;
}
}
int main()
{
std::thread thread(PrintMessage, "message from a child thread.");
PrintMessage("Message from a main thread");
thread.join();
return 0;
}
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.wait(lock);// wait을 하는 순간 lock을 풀어준다. 그래야 다른 스레드가 event를 날리기 위해 동작 할 수 있으니까...
val = sQueue.front();
sQueue.pop();
}
std::cout << val << std::endl;
}
}
void Produce()
{
std::unique_lock<std::mutex> lock(sQueueLock);
sQueue.push(1);
// Produce가 먼저 실행 되었을 때 하자 발생, 이미 notify가 발생 되어서 Consume에서 wait이 평생 머물러 있게 됨.
sEvent.notify_one();
}
int main()
{
// 이 두 순서를 바뀐다고 하더라도 성공활 확률이 높을 뿐 근본적인 문제가 발생되지 않는다.
std::thread producer(Produce);
std::thread consumer(Consume);
consumer.join();
producer.join();
return 0;
}
static std::mutex sQueueLock;
static std::condition_variable sEvent;
static std::queue<int> sQueue;
void Consume()
{
while(true)
{
int val;
{
// queue에 데이터가 있을 때에만 넘어가서 Lock이 안 걸린다.
std::unique_lock<std::mutex> lock(sQueueLock);
sEvent.wait(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(Consume);
consumer.join();
producer.join();
return 0;
}
std::condition_variable::wait
while(!pred())
{
wait(lock);// 큐가 비어 있을 때만 잠든다.
}
while(sQueue.empty())
{
sEvent.wait(lock);
}
Ex)
static mutex sMutex;
static condition_variable sEvent;
static int seconds;
constexpr int MAX_SECONDS = 10;
void Timer()
{
while (true)
{
{
scoped_lock<mutex> lock(sMutex);
cout << seconds << endl;
}
this_thread::sleep_for(chrono::seconds(1));
{
unique_lock<mutex> lock(sMutex);
seconds++;
sEvent.notify_one();
}
}
}
void Resetter()
{
while (true)
{
unique_lock<mutex> lock(sMutex);
sEvent.wait(lock, [] { return seconds >= MAX_SECONDS; });
seconds = 0;
cout << "Reset: " << seconds << endl;
}
}
void AutoResetTimerExample()
{
thread timer(Timer);
thread resetter(Resetter);
resetter.join();
timer.join();
}