/* Create a new thread, starting with execution of START-ROUTINE getting passed ARG. Creation attributed come from ATTR. The new handle is stored in *NEWTHREAD. */ externintpthread_create(pthread_t *__restrict __newthread, constpthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), void *__restrict __arg) __THROWNL __nonnull((1, 3));
/* Make calling thread wait for termination of the thread TH. The exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN is not NULL. This function is a cancellation point and therefore not marked with __THROW. */ externintpthread_join(pthread_t __th, void **__thread_return);
❯ valgrind --tool=helgrind ./main-race ==23772== Command: ./main-race ==23772== ==23772== ---Thread-Announcement------------------------------------------ ==23772== ==23772== Thread #1 is the program's root thread ==23772== ==23772== ---Thread-Announcement------------------------------------------ ==23772== ==23772== Thread #2 was created ==23772== at 0x49979F3: clone (clone.S:76) ==23772== by 0x49988EE: __clone_internal (clone-internal.c:83) ==23772== by 0x49066D8: create_thread (pthread_create.c:295) ==23772== by 0x49071FF: pthread_create@@GLIBC_2.34 (pthread_create.c:828) ==23772== by 0x48572A6: pthread_create_WRK (hg_intercepts.c:445) ==23772== by 0x4858BB2: pthread_create@* (hg_intercepts.c:478) ==23772== by 0x109564: Pthread_create (mythreads.h:49) ==23772== by 0x109654: main (main-race.c:16)
由上面输出信息可知程序有一个主线程#1和一个由程序创建的子线程#2。
1 2 3 4 5 6 7 8 9 10 11
==23772== Possible data race during read of size 4 at 0x10C014 by thread #1 ==23772== Locks held: none ==23772== at 0x109655: main (main-race.c:17) ==23772== ==23772== This conflicts with a previous write of size 4 by thread #2 ==23772== Locks held: none ==23772== at 0x109609: worker (main-race.c:10) ==23772== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==23772== by 0x4906AC2: start_thread (pthread_create.c:442) ==23772== by 0x4997A03: clone (clone.S:100) ==23772== Address 0x10c014 is 0 bytes inside data symbol "balance"
==23772== Possible data race during write of size 4 at 0x10C014 by thread #1 ==23772== Locks held: none ==23772== at 0x10965E: main (main-race.c:17) ==23772== ==23772== This conflicts with a previous write of size 4 by thread #2 ==23772== Locks held: none ==23772== at 0x109609: worker (main-race.c:10) ==23772== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==23772== by 0x4906AC2: start_thread (pthread_create.c:442) ==23772== by 0x4997A03: clone (clone.S:100) ==23772== Address 0x10c014 is 0 bytes inside data symbol "balance"
❯ valgrind --tool=helgrind ./main-deadlock ==7873== ---Thread-Announcement------------------------------------------ ==7873== Thread #3 was created ==7873== ---------------------------------------------------------------- ==7873== ==7873== Thread #3: lock order "0x10C040 before 0x10C080" violated ==7873== ==7873== Observed (incorrect) order is: acquisition of lock at 0x10C080 ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109639: worker (main-deadlock.c:16) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== ==7873== followed by a later acquisition of lock at 0x10C040 ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109648: worker (main-deadlock.c:17) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== ==7873== Required order was established by acquisition of lock at 0x10C040 ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109619: worker (main-deadlock.c:13) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== ==7873== followed by a later acquisition of lock at 0x10C080 ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109628: worker (main-deadlock.c:14) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== ==7873== Lock at 0x10C040 was first observed ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109619: worker (main-deadlock.c:13) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== Address 0x10c040 is 0 bytes inside data symbol "m1" ==7873== ==7873== Lock at 0x10C080 was first observed ==7873== at 0x4853D81: mutex_lock_WRK (hg_intercepts.c:944) ==7873== by 0x4858FBF: pthread_mutex_lock (hg_intercepts.c:960) ==7873== by 0x1093A6: Pthread_mutex_lock (mythreads.h:23) ==7873== by 0x109628: worker (main-deadlock.c:14) ==7873== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==7873== by 0x4906AC2: start_thread (pthread_create.c:442) ==7873== by 0x4997A03: clone (clone.S:100) ==7873== Address 0x10c080 is 0 bytes inside data symbol "m2" ==7873== ==7873== ==7873== ==7873== Use --history-level=approx or =none to gain increased speed, at ==7873== the cost of reduced accuracy of conflicting-access information ==7873== For lists of detected and suppressed errors, rerun with: -s ==7873== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 7)
❯ valgrind --tool=helgrind ./main-signal ==27862== Command: ./main-signal ==27862== this should print first ==27862== ---Thread-Announcement------------------------------------------ ==27862== ==27862== Thread #2 was created ==27862== ==27862== ---Thread-Announcement------------------------------------------ ==27862== ==27862== Thread #1 is the program's root thread ==27862== ==27862== ---------------------------------------------------------------- ==27862== ==27862== Possible data race during write of size 4 at 0x10C014 by thread #2 ==27862== Locks held: none ==27862== at 0x109633: worker (main-signal.c:13) ==27862== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==27862== by 0x4907AC2: start_thread (pthread_create.c:442) ==27862== by 0x4998A03: clone (clone.S:100) ==27862== ==27862== This conflicts with a previous read of size 4 by thread #1 ==27862== Locks held: none ==27862== at 0x109684: main (main-signal.c:20) ==27862== Address 0x10c014 is 0 bytes inside data symbol "done" ==27862== ==27862== ---------------------------------------------------------------- ==27862== ==27862== Possible data race during read of size 4 at 0x10C014 by thread #1 ==27862== Locks held: none ==27862== at 0x109684: main (main-signal.c:20) ==27862== ==27862== This conflicts with a previous write of size 4 by thread #2 ==27862== Locks held: none ==27862== at 0x109633: worker (main-signal.c:13) ==27862== by 0x48574A0: mythread_wrapper (hg_intercepts.c:406) ==27862== by 0x4907AC2: start_thread (pthread_create.c:442) ==27862== by 0x4998A03: clone (clone.S:100) ==27862== Address 0x10c014 is 0 bytes inside data symbol "done" ==27862== this should print last ==27862== ==27862== Use --history-level=approx or =none to gain increased speed, at ==27862== the cost of reduced accuracy of conflicting-access information ==27862== For lists of detected and suppressed errors, rerun with: -s ==27862== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 62 from 35)
// // simple synchronizer: allows one thread to wait for another // structure "synchronizer_t" has all the needed data // methods are: // init (called by one thread) // wait (to wait for a thread) // done (to indicate thread is done) // typedefstruct __synchronizer_t { pthread_mutex_t lock; pthread_cond_t cond; int done; } synchronizer_t;
❯ valgrind --tool=helgrind ./main-signal-cv ==36705== Command: ./main-signal-cv ==36705== this should print first this should print last ==36705== ==36705== Use --history-level=approx or =none to gain increased speed, at ==36705== the cost of reduced accuracy of conflicting-access information ==36705== For lists of detected and suppressed errors, rerun with: -s ==36705== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7)