#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std::literals;
std::mutex m;
int shared_data = 0;
void consumer()
{
// 읽는다
std::lock_guard<std::mutex> lg(m);
std::cout << "consume : " << shared_data << std::endl;
}
void producer()
{
// 쓴다
std::lockguard<std::mutex> lg(m);
shared_data = 100;
std::cout << "produce : " << shared_data << std::endl;
}
int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
}
// 만약 쓰기전에 읽는 경우가 발생한다면??
// 데이터가 써지고 읽게 만들어보자
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>
using namespace std::literals;
std::mutex m;
std::condition_variable cv;
int shared_data = 0;
void consumer()
{
// std::lock_guard<std::mutex> lg(m);
std::unique_lock<std::mutex> ul(m); // condition variable은 unique_lock만 지원됨
cv.wait(ul); // wait에 들어가면 lock을 풀고 대기, 신호가 오면 다시 lock을 걸고 아래라인으로 넘어간다.
std::cout << "consume : " << shared_data << std::endl;
}
void producer()
{
{
std::lockguard<std::mutex> lg(m);
shared_data = 100;
std::cout << "produce : " << shared_data << std::endl;
// 이건 하나의 팁인데 lock을 풀고 notify_one을 주는게 신호를 바로 받을수 있어서 속도에서 좋다
}
cv.notify_one();
}
int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
}
또 다른 문제
void consumer()
{
std::this_thread::sleep_for(200ms);
std::unique_lock<std::mutex> ul(m);
cv.wait(ul); // 2. notify를 기다리게 되면서 무한정 기다리게 된다.
std::cout << "consume : " << shared_data << std::endl;
}
void producer()
{
{
std::lockguard<std::mutex> lg(m);
shared_data = 100;
std::cout << "produce : " << shared_data << std::endl;
}
cv.notify_one(); // 1. notify를 먼저주고
}
해결해 보자
std::mutex m;
std::condition_variable cv;
bool data_ready = false;
int shared_data = 0;
//...
void consumer()
{
std::this_thread::sleep_for(200ms);
std::unique_lock<std::mutex> ul(m);
cv.wait(ul, []() { return data_ready; });
std::cout << "consume : " << shared_data << std::endl;
}
void producer()
{
{
std::lockguard<std::mutex> lg(m);
shared_data = 100;
data_ready = true;
std::cout << "produce : " << shared_data << std::endl;
}
cv.notify_one();
}
좀 더 발전시켜보자
std::mutex m;
std::condition_variable cv;
bool data_ready = false;
bool data_process = false;
int shared_data = 0;
//...
void consumer()
{
std::unique_lock<std::mutex> ul(m);
cv.wait(ul, []() { return data_ready; });
std::cout << "consume : " << shared_data << std::endl;
// 데이터가 잘 들어왔음을 알린다
data_process = true;
ul.unlock();
cv.notify_one();
}
void producer()
{
{
std::lockguard<std::mutex> lg(m);
shared_data = 100;
data_ready = true;
std::cout << "produce : " << shared_data << std::endl;
}
cv.notify_one();
std::unique_lock<std::mutex> ul(m);
cv.wait(ul, [](){return data_process;});
}