mardi 24 juillet 2018

c++11 std::mutex locking same thread

I am studying (refreshing) C++ now. As part of refreshing, I tried to check std::mutex behavior by me below code. It basically trys to do 'Manual lock/unlock', 'std::lock_guard over mutex' and 'try_lock over std::mutex'. When I refer std::mutex::try_lock, it says if same thread tries to lock again, it is a dead-lock. But I am checking try_lock(), which as per above link description, it should give false. But somehow, std::mutex able to lock already locked mutex. I tried googling/stackoverflow, not able to find cause of this behavior. Could you let me know, why std::mutex able to lock again after locking in same thread?

Code:

#include <iostream>
#include <mutex>

template <typename BASICLOCKABLE>
void ManualLockUnlock(BASICLOCKABLE & mut, std::string msg)
{
    mut.lock();
    std::cout << msg << "Manually locked, unlocked\n";

    if(mut.try_lock())
    {
        std::cout << msg << "able to try_lock after manual lock\n";
        mut.unlock();
    }
    else
    {
        std::cout << msg << "UNABLE to try_lock after manual lock\n";
    }
    mut.unlock();
    std::cout << std::endl;
}

template <typename BASICLOCKABLE>
void lock_guard(BASICLOCKABLE & mut, std::string msg)
{
    std::lock_guard<BASICLOCKABLE> lc(mut);
    std::cout << msg << "lock_guard locked, unlocked\n";

    if(mut.try_lock())
    {
        std::cout << msg << "able to try_lock again inside lock_guard\n";
        mut.unlock();
    }
    else
    {
        std::cout << msg << "UNABLE to try_lock again inside lock_guard\n";
    }
    {
        std::lock_guard<BASICLOCKABLE> lc2(mut);
        std::cout << msg << "SECOND LEVEL lock_guard locked, unlocked\n";
    }
    std::cout << std::endl;
}

template <typename BASICLOCKABLE>
void try_lock(BASICLOCKABLE & mut, std::string msg)
{
    mut.try_lock();
    std::cout << msg << "try_lock locked, unlocked\n";

    if(mut.try_lock())
    {
        std::cout << msg << "able to try_lock again inside try_lock\n";
        mut.unlock();
    }
    else
    {
        std::cout << msg << "UNABLE to try_lock again inside try_lock\n";
    }

    mut.unlock();
    std::cout << std::endl;
}

int main()
{
    std::string msg;

    std::mutex mut;
    msg = "std::mutex ";
    ManualLockUnlock(mut, msg);
    lock_guard(mut, msg);
    try_lock(mut, msg);

    std::recursive_mutex    recMut;
    msg = "std::recursive_mutex ";

    ManualLockUnlock(recMut, msg);
    lock_guard(recMut, msg);
    try_lock(recMut, msg);
}

Compile command:

g++ lock_guard.cpp -std=c++11

Output:

std::mutex Manually locked, unlocked
std::mutex able to try_lock after manual lock

std::mutex lock_guard locked, unlocked
std::mutex able to try_lock again inside lock_guard
std::mutex SECOND LEVEL lock_guard locked, unlocked

std::mutex try_lock locked, unlocked
std::mutex able to try_lock again inside try_lock

std::recursive_mutex Manually locked, unlocked
std::recursive_mutex able to try_lock after manual lock

std::recursive_mutex lock_guard locked, unlocked
std::recursive_mutex able to try_lock again inside lock_guard
std::recursive_mutex SECOND LEVEL lock_guard locked, unlocked

std::recursive_mutex try_lock locked, unlocked
std::recursive_mutex able to try_lock again inside try_lock

Compiler that I am using:

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Aucun commentaire:

Enregistrer un commentaire