Reputation: 1921
I was reading differences between binary semaphore and mutex (Difference between binary semaphore and mutex) and one thing that i want to verify is that when a task locks (acquires) a mutex only it can unlock (release) it. If another task tries to unlock a mutex it hasn’t locked (thus doesn’t own) then an error condition is encountered and, most importantly, the mutex is not unlocked and for that i created below code in c++14:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;
int counter;
int i;
std::mutex g_pages_mutex;
void increment()
{
std::cout<<"increment...."<<std::endl;
g_pages_mutex.lock();
bool flag = g_pages_mutex.try_lock();
std::cout<<"increment Return value is "<<flag<<std::endl;
counter++;
std::this_thread::sleep_for(5s);
}
void increment1()
{
std::this_thread::sleep_for(5s);
std::cout<<"increment1...."<<std::endl;
g_pages_mutex.unlock();
counter++;
bool flag = g_pages_mutex.try_lock();
std::cout<<"increment1 Return value is "<<flag<<std::endl;
}
int main()
{
counter = 0;
std::thread t(increment);
std::thread t1(increment1);
t.join();
t1.join();
return 0;
}
However with this example I was able to unlock mutex from thread that doesn't own that , so just want is there some understanding gap or is this issue in c++14 std::mutex ?
Upvotes: 2
Views: 4965
Reputation: 7111
From cppreference std::mutex
(emphasis mine):
The behavior of a program is undefined if a mutex is destroyed while still owned by any threads, or a thread terminates while owning a mutex.
From the same site on std::mutex::try_lock
and as TC points out in their answer:
If try_lock is called by a thread that already owns the mutex, the behavior is undefined.
And also std::mutex::unlock
and as TC points out in their answer:
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.
Both your functions and threads cause undefined behaviour:
increment
calls lock()
and then try_lock()
: undefined behaviourincrement1
calls unlock()
before owning the mutex: undefined behaviourRemoving the try_lock()
from increment
will still result in undefined behaviour if you don't call unlock()
before the thread ends.
You should prefer to use a std::lock_guard
, or for a simple int
you could also use std::atomic
Upvotes: 2
Reputation: 37549
The precondition for calling unlock
is holding an ownership of the mutex, according to (std)30.4.1.2:
The expression m.unlock() shall be well-formed and have the following semantics:
Requires: The calling thread shall own the mutex.
Since thread executing increment1
does not hold the ownership of the mutex it detonated undefined behavior.
Upvotes: 3
Reputation: 137315
Calling try_lock
on a std::mutex
(which is not recursive) owned by the calling thread, calling unlock
on a mutex not owned by the calling thread, and ending a thread while holding a mutex, all result in undefined behavior.
It might appear to succeed, it might fail and throw an exception, it might format your hard drive, it might summon nasal demons, it might time travel and correct your code for you, or it might do something else. As far as the standard is concerned, anything is permissible.
Upvotes: 10