int main(){
std::mutex mut;
mut.lock();
cout<<"1111\n";
mut.lock();
cout<<"2222\n";
return 0;
}
Why does this code work and output 2222? Shouldn't it block at the second lock()? In the mutex source code, the operation lock throws an exception. Shouldn't it block and wait? I use try{...}catch(exception& e){} to catch this exception but it doesn't work.
void
lock()
{
int __e = __gthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
It cannot. Your code has undefined behavior.
From cppreference:
If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. An implementation that can detect the invalid usage is encouraged to throw a std::system_error with error condition resource_deadlock_would_occur instead of deadlocking.
Reading on, one might get the impression that calling lock on the same thread would trigger an exception always:
Exceptions
Throws std::system_error when errors occur, including errors from the
underlying operating system that would prevent lock from meeting its
specifications. The mutex is not locked in the case of any exception
being thrown.
However, there is not necessarily an exception when you call lock in the same thread. Only if the implementation can detect such invalid use and only if the implementation is kind enough to actually throw an exception.
Looking into the standard we find:
1 The class mutex provides a non-recursive mutex with exclusive
ownership semantics. If one thread owns a mutex object, attempts by
another thread to acquire ownership of that object will fail (for
try_lock()) or block (for lock()) until the owning thread has
released ownership with a call to unlock().
2 [Note: After a thread A has called unlock(), releasing a mutex, it is possible for another thread B to lock the same mutex, observe that
it is no longer in use, unlock it, and destroy it, before thread A
appears to have returned from its unlock call. Implementations are
required to handle such scenarios correctly, as long as thread A
doesn't access the mutex after the unlock call returns. These cases
typically occur when a reference-counted object contains a mutex that
is used to protect the reference count. — end note ]
3 The class mutex meets all of the mutex requirements ([thread.mutex.requirements]). It is a standard-layout class
([class.prop]).
4 [Note: A program can deadlock if the thread that owns a mutex object calls lock() on that object. If the implementation can detect the
deadlock, a resource_deadlock_would_occur error condition might be
observed. — end note ]
5 The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread terminates while owning a mutex
object.
It only says "can deadlock" and "might be observed" but otherwise it does not define what happens when you call lock in the same thread.
PS Requiring to throw an excpetion in this case would make calling lock more expensive without any real benefit. Calling lock twice in the same thread is something that you should just not do. Actually you shouldn't call std::mutex::lock directly at all, because manually releasing the lock is not exception safe:
// shared block - bad
{
mut.lock();
// ... code ...
mut.unlock();
}
If ...code.. throws an exception then mut is never unlocked. The way to solve that is RAII and fortunately the standard library offers lots of RAII-helpers for locks, eg std::lock_guard:
// shared block - good
{
std::lock_guard<std::mutex> lock(mut);
// ... code ...
}
TL;DR Don't do it.
If your code relies on that exception then you have more severe problems than not getting that exception.
You are working with a single thread. You should read on what a mutex really does and when/how it is used.
As of why it outputs 2222, it might as well output anything else or even make your neighborhood explode, since:
If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock.
https://en.cppreference.com/w/cpp/thread/mutex/lock
Related
I wrote some code before but I realized it has a very bad code style so I changed it.
I changed the A.unlock inside of the if block. I know if the if never run then this thread will unlock the mutex which does not belong to itself and then it will return an undefined behavior.
My question is, if it returns an undefined behavior, will the logic here still work? Because if thread t1 didn't have the lock, t1 unlock the mutex A will return undefine behavior and the mutex will still be held by the thread which holds it right? And it will not affect the other logic in this code.
My old code works as same as I put the unlock part inside of the if block. So that's why I am curious how can this work.
mutex A;
if(something)
{
A.lock();
}
A.unlock();
When calling unlock on a mutex, the mutex must be owned by the current thread or the behavior is undefined. Undefined behavior means anything can happen, including the program appearing to run correctly, the program crashing, or memory elsewhere getting corrupted and a problem not being visible until later.
Normally a mutex is not used directly; one of the other standard classes (like std::unique_lock or std::lock_guard are used to manage it. Then you won't have to worry about unlocking the mutex.
You should consider using std::lock_guard :
mutex A;
if (something)
{
lock_guard<mutex> lock(A);
}
It is an undefined behavior to unlock a mutex you haven't locked. It may work on some cases for so many times but some day it will break and behave differently.
You can use a lock_guard in your case and forget about lock/unlock
std::lock_guard<std::mutex> lock(A);
The ISO C++ standard has this to say on the matter, in [thread.mutex.requirements.mutex] (my emphasis):
The expression m.unlock() shall be well-formed and have the following semantics:
Requires: The calling thread shall own the mutex.
That means what you are doing is a violation of the standard and is therefore undefined. It may work, or it may delete all your files while playing the derisive_maniacal_laughter.mp3 file :-)
Bottom line, don't do it.
I also wouldn't put the unlock inside the loop since modern C++ has higher-level mechanisms for dealing with auto-release of resources. In this case, it's a lock guard:
std::mutex mtxProtectData; // probably defined elsewhere (long-lived)
: : :
if (dataNeedsChanging) {
std::lock_guard<std::mutex> mtxGuard(mtxProtectData);
// Change data, mutex will unlock at brace below
// when mtxGuard goes out of scope.
}
I've been trying to learn how to multithread and came up with the following understanding. I was wondering if I'm correct or far off and, if I'm incorrect in any way, if someone could give me advice.
To create a thread, first you need to utilize a library such as <thread> or any alternative (I'm using boost's multithreading library to get cross-platform capabilities). Afterwards, you can create a thread by declaring it as such (for std::thread)
std::thread thread (foo);
Now, you can use thread.join() or thread.detach(). The former will wait until the thread finishes, and then continue; while, the latter will run the thread alongside whatever you plan to do.
If you want to protect something, say a vector std::vector<double> data, from threads accessing simultaneously, you would use a mutex.
Mutex's would be declared as a global variable so that they may access the thread functions (OR, if you're making a class that will be multithreaded, the mutex can be declared as a private/public variable of the class). Afterwards, you can lock and unlock a thread using a mutex.
Let's take a quick look at this example pseudo code:
std::mutex mtx;
std::vector<double> data;
void threadFunction(){
// Do stuff
// ...
// Want to access a global variable
mtx.lock();
data.push_back(3.23);
mtx.unlock();
// Continue
}
In this code, when the mutex locks down on the thread, it only locks the lines of code between it and mtx.unlock(). Thus, other threads will still continue on their merry way until they try accessing data (Note, we would likely through a mutex in the other threads as well). Then they would stop, wait to use data, lock it, push_back, unlock it and continue. Check here for a good description of mutex's.
That's about it on my understanding of multithreading. So, am I horribly wrong or accurate?
Your comments refer to "locking the whole thread". You can't lock part of a thread.
When you lock a mutex, the current thread takes ownership of the mutex. Conceptually, you can think of it as the thread places its mark on the mutex (stores its threadid in the mutex data structure). If any other thread comes along and attempts to acquire the same mutex instance, it sees that the mutex is already "claimed" by somebody else and it waits until the first thread has released the mutex. When the owning thread later releases the mutex, one of the threads that is waiting for the mutex can wake up, acquire the mutex for themselves, and carry on.
In your code example, there is a potential risk that the mutex might not be released once it is acquired. If the call to data.push_back(xxx) throws an exception (out of memory?), then execution will never reach mtx.unlock() and the mutex will remain locked forever. All subsequent threads that attempt to acquire that mutex will drop into a permanent wait state. They'll never wake up because the thread that owns the mutex is toast.
For this reason, acquiring and releasing critical resources like mutexes should be done in a manner that will guarantee they will be released regardless of how execution leaves the current scope. In other languages, this would mean putting the mtx.unlock() in the finally section of a try..finally block:
mtx.lock();
try
{
// do stuff
}
finally
{
mtx.unlock();
}
C++ doesn't have try..finally statements. Instead, C++ leverages its language rules for automatic disposal of locally defined variables. You construct an object in a local variable, the object acquires a mutex lock in its constructor. When execution leaves the current function scope, C++ will make sure that the object is disposed, and the object releases the lock when it is disposed. That's the RAII others have mentioned. RAII just makes use of the existing implicit try..finally block that wraps every C++ function body.
Someone please help me solve deadlock issues in c++ if possible with reference or examples.
Scenario would be like below.
Thread1 is locked by mutex and doing some operation, thread2 and thread3 are in waiting state for thread1 to unlock to access the resource.
Some abort/unexpected thing happened -- thread1 was terminated and didn't get the unlock, thread2 and thread3 are still waiting.
How to save the main thread (mean nothing should happen to main thread) in such situations.
Please throw some light how to solve such issues in c++.
Thanks,
Sheik
Some abort/unexpected thing happened
Use s.th. like std::lock_guard to prevent 'hanging' locks due to exceptions or forgotten/unexpected, but necessary unlock() operations.
The principle is pretty simple and you can easily implement it for any mechanism that uses a pair of methods that correspond together in a 'lock/unlock' manner:
class LockObject // E.g. mutex or alike
{
public:
// ...
void lock();
void unlock();
};
Bind the guard classes constructor to a reference to the lock object's instance and call lock() in the constructor and unlock() in the destructor:
template<typename T>
class LockGuard
{
public:
LockGuard(T& lockObject)
: lockObject_(lockObject)
{
lockObject_.lock();
}
~LockGuard()
{
lockObject_.unlock();
}
private:
T& lockObject_;
};
Use LockGuard like this:
// Some scope providing 'LockObject lockObject'
{ LockGuard<LockObject> lock(lockObject)
// Do s.th. when lockObject is locked
} // Call of lockObject.unlock() is guaranteed at least here, no matter what
// (exception, goto, break, etc.) caused leaving the block's scope.
Generally threads should not terminate unexpectedly. You may try using try/catch blocks. If you still want to free resources when a thread terminates unexpectedly, you may create a monitor thread that waits for the termination of the first thread.
On Windows, you can use something as ::WaitForSingleObject(m_htThread, INFINITE).
Once the 1st thread had been terminated, you may proceed with freeing abandoned locks.
Maybe you'll want to add some flag which indicates if the termination was graceful.
You'll probably also have to remember which thread is locking which object.
As said, I wouldn't recommend using such method, but on extreme cases.
The way to solve deadlocks in any language or platform is always the same.
Always acquire the locks in the same order.
EDIT: However you have misdescribed your problem. This is not a deadlock. A deadlock is a circular chain of locks. This is simply an unreleased lock, i.e. a lock leak. The solution is the same as any other resource leak: don't. In C++ that means releasing resources in destructors, and ensuring that destructors are called. Somehow your thread has terminated without doing that. Find that problem and fix it.
I wrote the following code to test my understanding of std::mutex
int main() {
mutex m;
m.lock();
m.lock(); // expect to block the thread
}
And then I got a system_error: device or resource busy. Isn't the second m.lock() supposed to block the thread?
From std::mutex:
A calling thread must not own the mutex prior to calling lock or try_lock.
and from std::mutex::lock:
If lock is called by a thread that already owns the mutex, the program may deadlock. Alternatively, if an implementation can detect the deadlock, a resource_deadlock_would_occur error condition may be observed.
and the exceptions clause:
Throws std::system_error when errors occur, including errors from the underlying operating system that would prevent lock from meeting its specifications. The mutex is not locked in the case of any exception being thrown.
Therefore it is not supposed to block the thread. On your platform, the implementation appears to be able to detect when a thread is already the owner of a lock and raise an exception. This may not happen on other platforms, as indicated in the descriptions.
Isn't the second m.lock() supposed to block the thread?
No, it gives undefined behaviour. The second m.lock() breaks this requirement:
C++11 30.4.1.2/7 Requires: If m is of type std::mutex or std::timed_mutex, the calling thread does not own the mutex.
It looks like your implementation is able to detect that the calling thread owns the mutex and gives an error; others may block indefinitely, or fail in other ways.
(std::mutex wasn't mentioned in the question when I wrote this answer.)
It depends on the mutex library and mutex type you're using - you haven't told us. Some systems provide a "recursive mutex" that is allowed to be called multiple times like this only if it happens from the same thread (then you must have a matching number of unlocks before another thread can lock it), other libraries consider this an error and may fail gracefully (as yours has) or have undefined behaviour.
I have some code which need to be thread safe and exception safe. The code below is a very simplified version of my problem :
#include <mutex>
#include <thread>
std::mutex mutex;
int n=0;
class Counter{
public:
Counter(){
std::lock_guard<std::mutex>guard(mutex);
n++;}
~Counter(){
std::lock_guard<std::mutex>guard(mutex);//How can I protect here the underlying code to mutex.lock() ?
n--;}
};
void doSomething(){
Counter counter;
//Here I could do something meaningful
}
int numberOfThreadInDoSomething(){
std::lock_guard<std::mutex>guard(mutex);
return n;}
I have a mutex that I need to lock in the destructor of an object. The problem is that my destructor should not throw exceptions.
What can I do ?
0) I cannot replace n with an atomic variable (of course it would do the trick here but that is not the point of my question)
1) I could replace my mutex with a spin lock
2) I could try and catch the locking into an infinite loop until I eventualy acquire the lock with no exception raised
None of those solution seems very appealing. Did you have the same problem ? How did you solve it ?
As suggested by Adam H. Peterson, I finally decided to write a no throw mutex :
class NoThrowMutex{
private:
std::mutex mutex;
std::atomic_flag flag;
bool both;
public:
NoThrowMutex();
~NoThrowMutex();
void lock();
void unlock();
};
NoThrowMutex::NoThrowMutex():mutex(),flag(),both(false){
flag.clear(std::memory_order_release);}
NoThrowMutex::~NoThrowMutex(){}
void NoThrowMutex::lock(){
try{
mutex.lock();
while(flag.test_and_set(std::memory_order_acquire));
both=true;}
catch(...){
while(flag.test_and_set(std::memory_order_acquire));
both=false;}}
void NoThrowMutex::unlock(){
if(both){mutex.unlock();}
flag.clear(std::memory_order_release);}
The idea is to have two mutex instead of only one. The real mutex is the spin mutex implemented with an std::atomic_flag. This spin mutex is protected by a std::mutex which could throw.
In a normal situation, the standard mutex is acquired and the flag is set with a cost of only one atomic operation. If the standard mutex cannot be locked immediately, the thread is going to sleep.
If for any reason the standard mutex throws, the mutex will enter its spin mode. The thread where the exception occured will then loop until it can set the flag. As no other thread is aware that this thread bybassed completely the standard mutex, they could spin too.
In the worst case scenario, this locking mechanism degrades to a spin lock. Most of the time it reacts just like a normal mutex.
This is a bad situation to be in. Your destructor is doing something that might fail. If failure to update this counter will irrecoverably corrupt your application, you may want to simply let the destructor throw. This will crash your application with a call to terminate, but if your application is corrupted, it may be better to kill the process and rely on some higher-level recovery scheme (such as a watchdog for a daemon or retrying execution for another utility). If failure to decrement the counter is recoverable, you should absorb the exception with a try{}catch() block and recover (or potentially save information for some other operation to eventually recover). If it's not recoverable, but it's not fatal, you may want to catch and absorb the exception and log the failure (being sure to log in an exception-safe way, of course).
It would be ideal if the code could be restructured such that the destructor doesn't do anything that can't fail. However, if your code is otherwise correct, failure while acquiring a lock is probably rare except in cases of constrained resources, so either absorbing or aborting on failure may very well be acceptable. For some mutexes, lock() is probably a no-throw operation (such as a spinlock using atomic_flag), and if you can use such a mutex, you can expect lock_guard to never throw. Your only worry in that situation would be deadlock.