Several processes access shared memory, locking it with the mutex and pthread_mutex_lock() for synchronization, and each process can be killed at any moment (in fact I described php-fpm with APC extension, but it doesn't matter).
Will the mutex be unlocked automatically, if the process locked the mutex and then was killed?
Or is there a way to unlock it automatically?
Edit: As it turns out, dying processes and threads have similar behavior in this situation, which depends on robust attribute of mutex.
That depends on the type of mutex. A "robust" mutex will survive the death of the thread/process. See this question: POSIX thread exit/crash/exception-crash while holding mutex
The next thread that will attempt to lock it will receive a EOWNERDEAD error code
Note: Collected information from the comments.
Related
I'm reading APUE Chapter 12(3rd edition) and it says: we can set either PTHREAD_MUTEX_STALLED or PTHREAD_MUTEX_ROBUST to the mutex. But I don't think we need mutex with attribute PTHREAD_MUTEX_STALLED, mutex should always "robust" , so that we can be notified if the side which locked the mutex is dead. If mutex is "stalled", we will be suspending forever.
And I know that Windows' mutex is always be "robust" and we will be notified with error WAIT_ABANDONED if the side which locked the mutex is dead. So, in what kind of scenario, we have to use "stalled" mutex, not "robust" mutex?
Thanks for your attention.
I see the following reasons why stalled mutex exists:
If robust mutex is used then everytime you try to lock a mutex, you have to check for EOWNERDEAD. So it requires an additional check.
If EOWNERDEAD is returned by pthread_mutex_lock() then you probably need to check all the state of shared objects that are relevant to that mutex has to checked and the mutex state has to reinstated by calling pthread_mutex_lock().
It's the default mutex attribute. Hence, no need for the application to call:pthread_mutexattr_setrobust().
Historical: early pthread implementations didn't have robust mutexes.
So all the above mentioned additional checks are only required if an application thinks a thread might die unexpectedly while holding a mutex, which is not how most threaded applications are designed. So it's a decision for an application to make if default behaviour (stalled) is sufficient or robust mutexes are needed.
I have a C application that uses pthreads.
There is a lock contention between two threads(say A and B) where A gets the lock first while B is waiting for the lock, Once A is done and releases the lock, B still doesn't get it and after a while A gets the lock again(A does acquire and release in a loop).
If I attach my process to gdb and pause thread A after it has given up the lock and manually continue on thread B, it then gets it and does what is needed.
This does not look like a dead lock to me.
What could be preventing thread B from getting the lock? Any help is greatly appreciated.
Sample Code:
Thread A:
while (true)
{
lock.acquire(lock)
// Do stuff
lock.release(lock)
// Do more stuff
}
Thread B:
lock.acquire(lock)
// Do some stuff
lock.release(lock)
It looks that you algorithm suffers from starvation, you should queue your access to the lock, see
pthreads: thread starvation caused by quick re-locking
or
Fair critical section (Linux)
As an answer to the comment, what is a mutex (pthread library)
A mutex is a lock (from Pthread library) that guarantees the following
three things:
Atomicity - Locking a mutex is an atomic operation,
meaning that the threads library assures you that if you lock a mutex,
no other thread can succeed in locking that mutex at the same time.
Singularity - If a thread managed to lock a mutex, it is assured that
no other thread will be able to lock the same mutex until the original
thread releases the lock.
Non-Busy Wait - If threadA attempts to lock a mutex that was locked
by threadB, the threadA will get suspended (and will not consume any
CPU resources) until the lock is freed by threadB. When threadB
unlocks the mutex, then the threadA will wake up and continue
execution, having the mutex locked by it.
It do not guaranty fairness.
If you are still interested in sort of reader writer fairness for pthread_rwlock_rdlock:
which are allowed to favour writers over readers to avoid writer starvation.
Another possibility is that your lock has been claimed earlier on the A thread preventing the lock/release to release fully (lock count thread stays too high).
Starvation is another strong possibility, but your question states "after a while A gets the lock again" indicating more than a few microseconds :), which should prevent starvation.
Is it possible that you return from A or use a continue statement, thus keeping the lock?
Is there a well defined behavior for POSIX mutex ownership in case of
Thread exits
Thread crashes
Thread crashes due to exception
Suppose thread-1 owns a mutex. And thread-2 is waiting to acquire the same mutex. And thread-1 goes the 1/2/3 scenario. What is the effect on thread-2 ?
PS : I believe the behavior for spin-lock is, NOT to unblock thread-2, with reasoning that the section protected by spin-lock is in bad shape anyways.
If you're worried about these issues, Robust Mutexes may be the tool you're looking for:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html
After a thread that owns a robust mutex terminates without unlocking it, the next thread that attempts to lock it will get EOWNERDEAD and become the new owner. This signals that it's responsible for cleaning up the state the mutex protects, and marking it consistent again with the pthread_mutex_consistent function before unlocking it. Unlocking it without marking it consistent puts the mutex in a permanently unrecoverable state.
Note that with robust mutexes, all code that locks the mutex must be aware of the possibility that EOWNERDEAD could be returned.
It's really simple. If you don't explicitly unlock the mutex, it remains locked, regardless of what happened or why. This is c, not ruby on rails or visual basic.
C Programming:
What happens when a thread tries to acquire a mutex lock, and fails to get it?
Does it go to sleep?
Will the thread be woken up when pthread_mutex_unlock(&mutex); is called?
Then try to obtain the lock again?
From the man page:
The pthread_mutex_lock() function locks mutex. If the mutex is already locked, the calling thread will block until the mutex becomes available.
So yes - your thread is blocked until the lock is available and it can obtain it.
Yes, it is a blocking call and will block until it gets the lock.
The non-blocking version is pthread_mutex_trylock(pthread_mutex_t *mutex) and will return EBUSY if someone else has the lock, or 0 if it got the lock. (Or some other error, of course)
Normally, pthread_mutex_lock cannot return until it acquires the lock, even if this means that it never returns (deadlock). There are a few notable exceptions though:
For recursive mutexes, it can return EAGAIN if the maximum reference count would be exceeded.
For error-checking mutexes, it can return EDEADLK if the thread tries to lock a mutex it already holds a lock on.
For robust mutexes, it can return EOWNERDEAD if another process died while holding the (shared) mutex. In this case, despite getting an error return, the caller holds the mutex lock and can mark the mutex-protected state valid again by calling pthread_mutex_consistent.
For robust mutexes whose owner died and for which the new owner called pthread_mutex_unlock without calling pthread_mutex_consistent first, it will return ENOTRECOVERABLE.
There may be a few cases I missed. Note that none of these apply to normal mutexes (PTHREAD_MUTEX_NORMAL type) without the robust attribute set, so if you only use normal mutexes, you can reasonably assume the call never returns without succeeding.
From the POSIX standard:
If the mutex is already locked, the calling thread shall block until the mutex becomes available.
(...)
If there are threads blocked on the mutex object referenced by mutex when pthread_mutex_unlock() is called, resulting in the mutex becoming available, the scheduling policy shall determine which thread shall acquire the mutex.
Where the "resulting in" clause is necessary because
(In the case of PTHREAD_MUTEX_RECURSIVE mutexes, the mutex shall become available when the count reaches zero and the calling thread no longer has any locks on this mutex.)
Suppose there are two threads, the main thread and say thread B(created by main). If B acquired a mutex(say pthread_mutex) and it has called pthread_exit without unlocking the lock. So what happens to the mutex? Does it become free?
nope. The mutex remaines locked. What actually happens to such a lock depends on its type, You can read about that here or here
If you created a robust mutex by setting up the right attributes before calling pthread_mutex_init, the mutex will enter a special state when the thread that holds the lock terminates, and the next thread to attempt to acquire the mutex will obtain an error of EOWNERDEAD. It is then responsible for cleaning up whatever state the mutex protects and calling pthread_mutex_consistent to make the mutex usable again, or calling pthread_mutex_unlock (which will make the mutex permanently unusable; further attempts to use it will return ENOTRECOVERABLE).
For non-robust mutexes, the mutex is permanently unusable if the thread that locked it terminates without unlocking it. Per the standard (see the resolution to issue 755 on the Austin Group tracker), the mutex remains locked and its formal ownership continues to belong to the thread that exited, and any thread that attempts to lock it will deadlock. If another thread attempts to unlock it, that's normally undefined behavior, unless the mutex was created with the PTHREAD_MUTEX_ERRORCHECK attribute, in which case an error will be returned.
On the other hand, many (most?) real-world implementations don't actually follow the requirements of the standard. An attempt to lock or unlock the mutex from another thread might spuriously succeed, since the thread id (used to track ownership) might have been reused and may now refer to a different thread (possibly the one making the new lock/unlock request). At least glibc's NPTL is known to exhibit this behavior.