Home > front end >  Showing the unlock from std::condition_variable::wait
Showing the unlock from std::condition_variable::wait

Time:10-12

I've read from https://en.cppreference.com/w/cpp/thread/condition_variable/wait that wait() "Atomically unlocks lock". How do I see this via std::cout? I am trying to understand conditional variables better on what they're actually doing. I've wrote an attempt below.

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;

condition_variable cv;
mutex m;
bool stopped = false;

void f1() {
    unique_lock<mutex> ul{m};
    cout << "f1: " << ul.owns_lock() << endl;
    cv.wait(ul, [&]{
        cout << "f1: " << ul.owns_lock() << endl;
        return stopped;
    });
    cout << "f1 RUNNING\n";
    cout << "f1: " << ul.owns_lock() << endl;
}


void f2() {
    lock_guard<mutex> lg{m};
    cout << "f2 RUNNING\n";
}

int main() {
    unique_lock<mutex> ul{m};
    thread t1(&f1);
    thread t2(&f2);

    cout << ul.owns_lock() << endl;
    this_thread::sleep_for(chrono::seconds(1));
    stopped = true;
    cv.notify_one();
    cout << ul.owns_lock() << endl;
    ul.unlock();
    cout << ul.owns_lock() << endl;
    this_thread::sleep_for(chrono::seconds(1));

    t1.join();
    t2.join();
    return 0;
}

CodePudding user response:

std::unique_lock and std::lock_guard work with any class type that satisfies the requirements of BasicLockable. So, just write your own class that wraps a std::mutex, then you can add whatever logging you want.

UPDATE: However, std:condition_variable only works with std::mutex specifically, so if you write your own mutex wrapper class then you will have to use std::condition_variable_any instead.

For example:

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;

struct LoggingMutex
{
    mutex m;

    void lock() {
        cout << "Locking" << endl;
        m.lock();
        cout << "Locked" << endl;
    }

    bool try_lock() {
        cout << "Attempting to lock" << endl;
        bool result = m.try_lock();
        cout << (result ? "Locked" : "Not locked") << endl;
        return result;
    }

    void unlock() {
        cout << "Unlocking" << endl;
        m.unlock()
        cout << "Unlocked" << endl;
    }
};

condition_variable_any cv;
LoggingMutex lm;
bool stopped = false;

void f1() {
    unique_lock<LoggingMutex> ul{lm};
    cout << "f1: " << ul.owns_lock() << endl;
    cv.wait(ul, [&]{
        cout << "f1: " << ul.owns_lock() << endl;
        return stopped;
    });
    cout << "f1 RUNNING\n";
    cout << "f1: " << ul.owns_lock() << endl;
}


void f2() {
    lock_guard<LoggingMutex> lg{lm};
    cout << "f2 RUNNING\n";
}

int main() {
    unique_lock<LoggingMutex> ul{lm};
    thread t1(&f1);
    thread t2(&f2);

    cout << ul.owns_lock() << endl;
    this_thread::sleep_for(chrono::seconds(1));
    stopped = true;
    cv.notify_one();
    cout << ul.owns_lock() << endl;
    ul.unlock();
    cout << ul.owns_lock() << endl;
    this_thread::sleep_for(chrono::seconds(1));

    t1.join();
    t2.join();
    return 0;
}
  • Related