Go back to Richel Bilderbeek's homepage.
Go back to Richel Bilderbeek's C++ page.
DRD is member of the valgrind tool suite and useful for
detecting deadlocks.
Below is an example of causing a deadlock, followed by using DRD to detect it.
Example
The example below will end in a deadlock: a thread calls the
member function MyClass::DoIt. This member function acquires the class
its only mutex. Then, MyClass::DoIt calls MyClass::DoItAgain, which starts by acquiring the same
mutex. Because this mutex is already in use, the program will wait infinitely.
Screen output:
The problem in this example can be solved by using a std::recursive_mutex instead.
Detecting a deadlock using DRD gives an indication of the problem.
DRD calls the program like this:
#!/bin/sh
valgrind --tool=drd --log-file=helgrind.txt ../CppDeadlock-build-desktop/./CppDeadlock
|
After terminating the program by CTRL-C, the following output is generated by DRD:
==8958== drd, a thread error detector
==8958== Copyright (C) 2006-2010, and GNU GPL'd, by Bart Van Assche.
==8958== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==8958== Command: ../CppDeadlock-build-desktop/./CppDeadlock
==8958== Parent PID: 8957
==8958==
==8958== Thread 2:
==8958== Recursive locking not allowed: mutex 0x804c194, recursion count 1, owner 2.
==8958== at 0x40295E0: pthread_mutex_lock (drd_pthread_intercepts.c:584)
==8958== by 0x80494EF: MyClass::DoIt() (in /home/richel/Projects/Website/CppDeadlock-build-desktop/CppDeadlock)
==8958== by 0x4399265: ??? (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==8958== by 0x4027E8B: vgDrd_thread_wrapper (drd_pthread_intercepts.c:281)
==8958== by 0x4027E8B: vgDrd_thread_wrapper (drd_pthread_intercepts.c:281)
==8958== by 0x42E1E98: start_thread (pthread_create.c:304)
==8958== by 0x44F273D: clone (clone.S:130)
==8958== mutex 0x804c194 was first observed at:
==8958== at 0x40295E0: pthread_mutex_lock (drd_pthread_intercepts.c:584)
==8958== by 0x804949C: MyClass::DoIt() (in /home/richel/Projects/Website/CppDeadlock-build-desktop/CppDeadlock)
==8958== by 0x4399265: ??? (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.14)
==8958== by 0x4027E8B: vgDrd_thread_wrapper (drd_pthread_intercepts.c:281)
==8958== by 0x4027E8B: vgDrd_thread_wrapper (drd_pthread_intercepts.c:281)
==8958== by 0x42E1E98: start_thread (pthread_create.c:304)
==8958== by 0x44F273D: clone (clone.S:130)
==8958==
|
From [1].
8.2.13. Hints and Tips for Effective Use of DRD
The following information may be helpful when using DRD:
Make sure that debug information is present in the executable being analyzed, such that DRD can print function name and line number information in stack traces. Most compilers can be told to include debug information via compiler option -g.
Compile with option -O1 instead of -O0. This will reduce the amount of generated code, may reduce the amount of debug info and will speed up DRD's processing of the client program. For more information, see also Getting started.
If DRD reports any errors on libraries that are part of your Linux distribution like e.g. libc.so or libstdc++.so, installing the debug packages for these libraries will make the output of DRD a lot more detailed.
When using C++, do not send output from more than one thread to std::cout. Doing so would not only generate multiple data race reports, it could also result in output from several threads getting mixed up. Either use printf or do the following:
* Derive a class from std::ostreambuf and let that class send output line by line to stdout. This will avoid that individual lines of text produced by different threads get mixed up.
* Create one instance of std::ostream for each thread. This makes stream formatting settings thread-local. Pass a per-thread instance of the class derived from std::ostreambuf to the constructor of each instance.
* Let each thread send its output to its own instance of std::ostream instead of std::cout.
|
- Valgrind user manual section 8.2.13
Go back to Richel Bilderbeek's C++ page.
Go back to Richel Bilderbeek's homepage.
