vendredi 4 août 2023

Understanding cppreference example on lock

While reading on c++ std::lock, I ran into the following example from the cppreference:

void assign_lunch_partner(Employee &e1, Employee &e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl;
    }
 
    // use std::lock to acquire two locks without worrying about 
    // other calls to assign_lunch_partner deadlocking us
    {
        std::lock(e1.m, e2.m);
        std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);
    // Equivalent code (if unique_locks are needed, e.g. for condition variables)
    //        std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
    //        std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
    //        std::lock(lk1, lk2);
    // Superior solution available in C++17
    //        std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
        }
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }
    send_mail(e1, e2);
    send_mail(e2, e1);
}

While I do understand the need for making io_mutex as static so that its status is shared among concurrent calls to assign_lunch_partner function (Please correct me if I'm wrong), but I don't understand the following:

  1. Why the lk object (lock_guard) was scoped? Is it because of the nature lock_guard?
  2. Then if lk is scoped, does not this mean that the lock will be released once gone out of scope?
  3. Why there are twice declaration of scoped lk (lock_guard)? At the beginning and just before updating lunch_partners vectors?

Aucun commentaire:

Enregistrer un commentaire