wip on deadlocks.yo

This commit is contained in:
Frank B. Brokken 2014-09-24 16:08:44 +02:00
parent 823960b567
commit 5f186d6744
2 changed files with 86 additions and 7 deletions

View file

@ -1,10 +1,50 @@
Although they should be avoided, hi(deadlock) em(Deadlocks) are frequently
encountered in multi threaded programs. A deadlock occurs when two locks
are required to process data, but one thread obtains the first lock and
another thread obtains the second lock. The C++11 standard defines a generic
hi(lock)tt(std::lock) function that can be used to help preventing
such situations. The tt(std::lock) function can be used to lock multiple
mutexes in one atomic action. Here is an example:
A deadlock occurs when two locks are required to process data, but one thread
obtains the first lock and another thread obtains the second lock. The C++11
standard defines the generic
hi(lock)tt(std::lock) and hi(try_lock)std::try_lock) functions that can be
used to help preventing such situations.
Before these functions can be used the tthi(mutex) header file must be
included
In the following overview tt(L1 &l1, ...) represents one or more
references to objects of lockable types:
ittq(void std::lock(L1 &l1, ...))
quote(
When the function returns locks were obtained on all tt(li)
objects. If a lock could not be obtained for at least one of the objects, then
all locks obtained so far are relased, even if the object for which no lock
could be obtained threw an exception.)
ittq(int std::try_lock(L1 &l1, ...))
quote(
This function calls the lockable objects' tt(try_lock) members. If all
locks could be obtained, then -1 is returned. Otherwise the (0-based) index of
the first argument which could not be locked is returned, releasing all
previously obtained locks)
)
As an example consider the following small multi-threaded program: The threads
use mutexes to obtain unique access to tt(cout) and an tt(int value). However,
tt(fun1) first locks tt(cout) (line 7), and then tt(value) (line 10); tt(fun2)
first locks tt(value) (line 16) and then tt(cout) (line 19). Clearly, if
tt(fun1) has locked tt(cout) tt(fun2) can't obtain the lock until tt(fun1) has
released it. Unfortunately, tt(fun2) has locked tt(value), and the functions
only release their locks when returning. But in order to access the
information in tt(value) tt(fun1) it must have obtained a lock on tt(value),
which it can't, as tt(fun2) has already locked tt(value): the threads are
waiting for each other, and neither thread gives in.
verbinclude(-ns4 //code examples/deadlock.cc)
A good recipe for avoiding deadlocks is to prevent nested (or multiple
mutex lock calls. But if multiple mutexes must be used, always obtain the
locks in the same order. Rather than doing this yourself, tt(std::lock) and
tt(std::try_lock) should be used whenever possible to obtain multiple mutex
locks. These functions accept multiple arguments, which must be lockable types
like tt(lock_guard, unique_lock,) or even a plain tt(mutex).
The recipe to aWhen using multiple locks
These functions can be
used to lock multiple mutexes in one atomic action. Here is an example:
verb(
struct SafeString
{

View file

@ -0,0 +1,39 @@
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
//code
int value;
mutex valueMutex;
mutex coutMutex;
void fun1()
{
lock_guard<mutex> lg1(coutMutex);
cout << "fun 1 locks cout\n";
lock_guard<mutex> lg2(valueMutex);
cout << "fun 1 locks value\n";
}
void fun2()
{
lock_guard<mutex> lg1(valueMutex);
cerr << "fun 2 locks value\n";
lock_guard<mutex> lg2(coutMutex);
cout << "fun 2 locks cout\n";
}
int main()
{
thread t1(fun1);
fun2();
t1.join();
}
//=