C++14에는 공유 뮤텍스(shared mutex)에 기반한 공유 락(shared lock)이 도입되었다.
shared_lock을 만들 때, defer_lock 옵션을 주지 않으면 lock() 메소드 호출 시점이 아니라 shared_lock 생성 시점에 락이 걸릴 수 있으니 주의할 것
#include <iostream>
#include <shared_mutex>
using namespace std;
int main(void)
{
shared_timed_mutex m;
shared_lock<shared_timed_mutex> lk(m, defer_lock);
lk.lock();
cout << "in shared lock" << endl;
lk.unlock();
return 0;
}
in shared lock
공유 락을 이용하여 두 개의 reader가 동시에 실행되는 예제임. 동시에 실행되다보니 출력이 겹쳐서 깨질 수 있다.
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
using namespace std;
string file = "original content.";
shared_timed_mutex file_mutex;
void read_content(int id)
{
string content;
shared_lock<shared_timed_mutex> lock(file_mutex, defer_lock);
lock.lock();
content = file;
cout << "read by reader #" << id << ": " << content << '\n';
}
void write_content()
{
file = "new content.";
cout << "new content saved\n";
}
int main(void)
{
thread reader1 { read_content, 1 };
thread reader2 { read_content, 2 };
thread writer { write_content };
reader1.join();
reader2.join();
writer.join();
cout << "done" << endl;
reader1 = thread { read_content, 3 };
reader1.join();
return 0;
}
여러 쓰레드가 동시에 표준 출력으로 출력을 하는 바람에 결과가 뒤죽박죽 섞였음을 볼 수 있음
read by reader #read by reader #2: new content.ent.
new content saved
1: new content.ent.
done
read by reader #3: new content.
lock_guard를 이용하여 표준 출력을 동기화한다. (공유 락과는 직접적인 관련은 없으나 표준 출력을 예쁘게 볼 수 있는 효과를 기대함)
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
using namespace std;
string file = "original content.";
mutex output_mutex;
shared_timed_mutex file_mutex;
void read_content(int id)
{
string content;
shared_lock<shared_timed_mutex> lock(file_mutex, defer_lock);
lock.lock();
content = file;
lock_guard<mutex> lg(output_mutex);
cout << "read by reader #" << id << ": " << content << endl;
}
void write_content()
{
file = "new content.";
lock_guard<mutex> lg(output_mutex);
cout << "new content saved" << endl;
}
int main(void)
{
thread reader1 { read_content, 1 };
thread reader2 { read_content, 2 };
thread writer { write_content };
reader1.join();
reader2.join();
writer.join();
cout << "done" << endl;
reader1 = thread { read_content, 3 };
reader1.join();
return 0;
}
표준 출력이 동기화되어 깨지지 않고 정돈되어 출력됨을 확인할 수 있다.
new content saved
read by reader #1: new content.ent.
read by reader #2: new content.ent.
done
read by reader #3: new content.