Software Workshop

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.