トルネード

毛利のメモ書き

std::shared_mutex, std::shared_timed_mutexを理解する

C++17では、std::shared_mutexが追加されています。 std::mutexとは違いstd::shared_lockが使えます。
std::shared_mutexは、std::mutexと同じようにstd:: lock_guardも使えます。

std::shared_mutex m1;
std::lock_guard<std::shared_mutex> lock(m1);

下記は、std:: lock_guardを使ったコードです。std::this_thread::sleep_for(1秒)1秒経過するまで次のスレッドは待機状態です。

int main()
{
    std::shared_mutex m1;
    std::vector<std::thread> thread_list;

    for (int i = 0; i < 10; i++)
    {
        thread_list.push_back((std::thread)[&m1, i]() {
            std::lock_guard<std::shared_mutex> lock(m1);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        });
    }

最初のスレッドだけをstd:: lock_guardし、残りをstd::shared_lockにして実行してみましょう。

template <typename T>
std::function<void()> func1(std::shared_mutex& m1, int i1)
{
    return [&m1, i1]() {
        T lock(m1);
        std::stringstream ss;
        ss << i1 << " %c" << std::endl;
        std::cout << System::sysUtils::datetimeformat(ss.str());
        std::this_thread::sleep_for(std::chrono::seconds(1));
    };
};

int main()
{
    //shared_mutex_test1 test1;
    std::shared_mutex m1;

    std::vector<std::thread> thread_list;

    for (int i = 0; i < 10; i++)
    {
        switch (i) {
            case 0:
                thread_list.push_back((std::thread)func1<std::lock_guard<std::shared_mutex> >(m1, i));
                break;
            default:
                thread_list.push_back((std::thread)func1<std::shared_lock<std::shared_mutex> >(m1, i));
                break;
        }
    }

実行すると下記のような結果が表示されます。

f:id:mojeld:20181226140409p:plain

最初のstd:: lock_guardが完了するまで他のスレッドは待っていて、スレッド0の処理終わってから他のスレッドが処理をしてるのが確認できます。

std::shared_mutexは、std:: lock_guardstd::shared_lockをうまく使ってスレッド制御ができるようです。

f:id:mojeld:20181226141617p:plain