以下来自 cppreference.com 的 C++ 代码说明了如何将
std::condition_variable
与 std::mutex
结合使用以促进线程间通信。
#include <condition_variable> //01
#include <iostream> //02
#include <mutex> //03
#include <string> //04
#include <thread> //05
//06
std::mutex m; //07
std::condition_variable cv; //08
std::string data; //09
bool ready = false; //10
bool processed = false; //11
//12
void worker_thread() { //13
// wait until main() sends data //14
std::unique_lock<std::mutex> lk(m); //15
cv.wait(lk, [] { return ready; }); //16
//17
// after the wait, we own the lock //18
std::cout << "Worker thread is processing data\n"; //19
data += " after processing"; //20
//21
// send data back to main() //22
processed = true; //23
std::cout << "Worker thread signals data processing completed\n"; //24
//25
// manual unlocking is done before notifying, to avoid waking up //26
// the waiting thread only to block again (see notify_one for details) //27
lk.unlock(); //28
cv.notify_one(); //29
} //30
//31
int main() { //32
std::thread worker(worker_thread); //33
//34
data = "Example data"; //35
// send data to the worker thread //36
{ //37
std::lock_guard<std::mutex> lk(m); //38
ready = true; //39
std::cout << "main() signals data ready for processing\n"; //40
} //41
cv.notify_one(); //42
//43
// wait for the worker //44
{ //42
std::unique_lock<std::mutex> lk(m); //46
cv.wait(lk, [] { return processed; }); //47
} //48
std::cout << "Back in main(), data = " << data << '\n'; //49
//50
worker.join(); //51
} //52
以下观察假设上述源代码存储在名为
a.cpp
的文件中。这些观察是使用 WSL2 Ubuntu 22.03.4(在 MS Windows 10 上运行)进行的。
执行检测代码时不会报告数据争用/争用条件:
$ clang++ -fsanitize=thread -g -O1 -Wall a.cpp; ./a.out
main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing
$ clang++ -g -Wall a.cpp; valgrind --tool=drd ./a.out
drd, a thread error detector
Copyright (C) 2006-2020, and GNU GPL'd, by Bart Van Assche.
Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
Command: ./a.out
main() signals data ready for processing
Probably a race condition: condition variable 0x10f118 has been signaled
but the associated mutex 0x10f0f0 is not locked by the signalling thread.
┌────────────┬────────────────────────────────┬────────────────────────┬────┐
│at 0x4E244C5│pthread_cond_signal_intercept │drd_pthread_intercepts.c│1248│
│by 0x4E244C5│pthread_cond_signal@* │drd_pthread_intercepts.c│1261│
│by 0x10A4D8 │main │a.cpp │ 42│
└────────────┴────────────────────────────────┴────────────────────────┴────┘
cond 0x10f118 was first observed at:
【TABLE 1】
┌────────────┬────────────────────────────────┬────────────────────────┬────┐
│at 0x4E217F0│pthread_cond_wait_intercept │drd_pthread_intercepts.c│1162│
│by 0x4E217F0│pthread_cond_wait@* │drd_pthread_intercepts.c│1170│
│by 0x10A44C │void std │condition_variable │ 103│
│ │::condition_variable │ │ │
│ │::wait<worker_thread() │ │ │
│ │::$_0>( │ │ │
│ │ std::unique_lock<std::mutex>&,│ │ │
│ │ worker_thread()::$_0 │ │ │
│ │) │ │ │
│by 0x10A36B │worker_thread() │a.cpp │ 16│
│... │ │ │ │
└────────────┴────────────────────────────────┴────────────────────────┴────┘
mutex 0x10f0f0 was first observed at:
【TABLE 2】
┌────────────┬────────────────────────────────┬────────────────────────┬────┐
│at 0x4E1B640│pthread_mutex_lock_intercept │drd_pthread_intercepts.c│ 942│
│by 0x4E1B640│pthread_mutex_lock@* │drd_pthread_intercepts.c│ 955│
│by 0x10A642 │__gthread_mutex_lock( │gthr-default.h │ 749│
│ │ pthread_mutex_t* │ │ │
│ │) │ │ │
│by 0x10A9C4 │std::mutex::lock() │std_mutex.h │ 100│
│by 0x10AA6B │std::unique_lock<std::mutex> │unique_lock.h │ 139│
│ │ ::lock() │ │ │
│by 0x10A720 │std::unique_lock<std::mutex> │unique_lock.h │ 69│
│ │ ::unique_lock(std::mutex&) │ │ │
│by 0x10A35B │worker_thread() │a.cpp │ 15│
│... │ │ │ │
└────────────┴────────────────────────────────┴────────────────────────┴────┘
Worker thread is processing data
Worker thread signals data processing completed
Thread 2:
Probably a race condition: condition variable 0x10f118 has been signaled
but the associated mutex 0x10f0f0 is not locked by the signalling thread.
┌────────────┬────────────────────────────────┬────────────────────────┬────┐
│at 0x4E244C5│pthread_cond_signal_intercept │drd_pthread_intercepts.c│1248│
│by 0x4E244C5│pthread_cond_signal@* │drd_pthread_intercepts.c│1261│
│by 0x10A3D9 │worker_thread() │a.cpp │ 29│
│... │ │ │ │
└────────────┴────────────────────────────────┴────────────────────────┴────┘
cond 0x10f118 was first observed at: See 【TABLE 1】
mutex 0x10f0f0 was first observed at: See 【TABLE 2】
Back in main(), data = Example data after processing
For lists of detected and suppressed errors, rerun with: -s
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 34 from 16)
如果进行以下更改,使
m
互斥量在cv.notify_one()
函数调用之前未解锁:
$ clang++ -g -Wall a.cpp; valgrind --tool=helgrind ./a.out
Helgrind, a thread error detector
Copyright (C) 2007-2017, and GNU GPL'd, by OpenWorks LLP et al.
Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
Command: ./a.out
---Thread-Announcement------------------------------------------
Thread #1 is the program's root thread
---Thread-Announcement------------------------------------------
Thread #2 was created
at 0x53729F3: clone (clone.S:76)
by 0x53738EE: __clone_internal (clone-internal.c:83)
by 0x52E16D8: create_thread (pthread_create.c:295)
by 0x52E21FF: pthread_create@@GLIBC_2.34 (pthread_create.c:828)
by 0x4E13585: pthread_create_WRK (hg_intercepts.c:445)
by 0x4E14A8C: pthread_create@* (hg_intercepts.c:478)
by 0x50FD328: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
by 0x10A849: std::thread::thread<void (&)(), , void>(void (&)()) (std_thread.h:143)
by 0x10A477: main (a.cpp:33)
----------------------------------------------------------------
Possible data race during read of size 4 at 0x10F0F8 by thread #1
Locks held: none
at 0x52E4F4A: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:94)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10A8C2: std::lock_guard<std::mutex>::lock_guard(std::mutex&) (std_mutex.h:229)
by 0x10A49F: main (a.cpp:38)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x10F0F8 by thread #1
Locks held: none
at 0x52E4F5D: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:170)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10A8C2: std::lock_guard<std::mutex>::lock_guard(std::mutex&) (std_mutex.h:229)
by 0x10A49F: main (a.cpp:38)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
----------------------------------------------------------------
Possible data race during read of size 4 at 0x10F0FC by thread #1
Locks held: none
at 0x52E4F60: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:172)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10A8C2: std::lock_guard<std::mutex>::lock_guard(std::mutex&) (std_mutex.h:229)
by 0x10A49F: main (a.cpp:38)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E4F60: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:172)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10AA6B: std::unique_lock<std::mutex>::lock() (unique_lock.h:139)
by 0x10A720: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (unique_lock.h:69)
by 0x10A35B: worker_thread() (a.cpp:15)
Address 0x10f0fc is 12 bytes inside data symbol "m"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x10F0FC by thread #1
Locks held: none
at 0x52E4F60: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:172)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10A8C2: std::lock_guard<std::mutex>::lock_guard(std::mutex&) (std_mutex.h:229)
by 0x10A49F: main (a.cpp:38)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E4F60: pthread_mutex_lock@@GLIBC_2.2.5 (pthread_mutex_lock.c:172)
by 0x4E1009A: mutex_lock_WRK (hg_intercepts.c:937)
by 0x4E14E73: pthread_mutex_lock (hg_intercepts.c:960)
by 0x10A642: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:749)
by 0x10A9C4: std::mutex::lock() (std_mutex.h:100)
by 0x10AA6B: std::unique_lock<std::mutex>::lock() (unique_lock.h:139)
by 0x10A720: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (unique_lock.h:69)
by 0x10A35B: worker_thread() (a.cpp:15)
Address 0x10f0fc is 12 bytes inside data symbol "m"
main() signals data ready for processing
----------------------------------------------------------------
Possible data race during write of size 4 at 0x10F0F8 by thread #1
Locks held: none
at 0x52E6A90: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E6A90: pthread_mutex_unlock@@GLIBC_2.2.5 (pthread_mutex_unlock.c:368)
by 0x4E10869: mutex_unlock_WRK (hg_intercepts.c:1184)
by 0x4E14E9F: pthread_mutex_unlock (hg_intercepts.c:1202)
by 0x10A692: __gthread_mutex_unlock(pthread_mutex_t*) (gthr-default.h:779)
by 0x10A9F4: std::mutex::unlock() (std_mutex.h:118)
by 0x10A8E7: std::lock_guard<std::mutex>::~lock_guard() (std_mutex.h:235)
by 0x10A4CC: main (a.cpp:42)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
----------------------------------------------------------------
Thread #1: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
at 0x4E109E8: pthread_cond_signal_WRK (hg_intercepts.c:1567)
by 0x4E14ED6: pthread_cond_signal@* (hg_intercepts.c:1588)
by 0x10A4D8: main (a.cpp:43)
----------------------------------------------------------------
Possible data race during write of size 8 at 0x10F120 by thread #1
Locks held: none
at 0x52E03F3: __atomic_wide_counter_add_relaxed (atomic_wide_counter.h:57)
by 0x52E03F3: __condvar_add_g1_start_relaxed (pthread_cond_common.c:52)
by 0x52E03F3: __condvar_quiesce_and_switch_g1 (pthread_cond_common.c:294)
by 0x52E03F3: pthread_cond_signal@@GLIBC_2.3.2 (pthread_cond_signal.c:77)
by 0x4E10A4A: pthread_cond_signal_WRK (hg_intercepts.c:1570)
by 0x4E14ED6: pthread_cond_signal@* (hg_intercepts.c:1588)
by 0x10A4D8: main (a.cpp:43)
This conflicts with a previous read of size 8 by thread #2
Locks held: none
at 0x52E09E4: __atomic_wide_counter_load_relaxed (atomic_wide_counter.h:30)
by 0x52E09E4: __condvar_load_g1_start_relaxed (pthread_cond_common.c:46)
by 0x52E09E4: __pthread_cond_wait_common (pthread_cond_wait.c:486)
by 0x52E09E4: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
by 0x10AD44: void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (std_thread.h:259)
Address 0x10f120 is 8 bytes inside data symbol "cv"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x10F0F8 by thread #1
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A60C: void std::condition_variable::wait<main::$_1>(std::unique_lock<std::mutex>&, main::$_1) (condition_variable:103)
by 0x10A4FD: main (a.cpp:48)
This conflicts with a previous write of size 4 by thread #2
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
----------------------------------------------------------------
Possible data race during read of size 8 at 0x10F120 by thread #2
Locks held: none
at 0x52E0900: __atomic_wide_counter_load_relaxed (atomic_wide_counter.h:30)
by 0x52E0900: __condvar_load_g1_start_relaxed (pthread_cond_common.c:46)
by 0x52E0900: __pthread_cond_wait_common (pthread_cond_wait.c:539)
by 0x52E0900: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
by 0x10AD44: void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (std_thread.h:259)
by 0x10AD14: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (std_thread.h:266)
by 0x10AC78: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (std_thread.h:211)
by 0x50FD252: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
by 0x4E13779: mythread_wrapper (hg_intercepts.c:406)
This conflicts with a previous write of size 8 by thread #1
Locks held: none
at 0x52E03F3: __atomic_wide_counter_add_relaxed (atomic_wide_counter.h:57)
by 0x52E03F3: __condvar_add_g1_start_relaxed (pthread_cond_common.c:52)
by 0x52E03F3: __condvar_quiesce_and_switch_g1 (pthread_cond_common.c:294)
by 0x52E03F3: pthread_cond_signal@@GLIBC_2.3.2 (pthread_cond_signal.c:77)
by 0x4E10A4A: pthread_cond_signal_WRK (hg_intercepts.c:1570)
by 0x4E14ED6: pthread_cond_signal@* (hg_intercepts.c:1588)
by 0x10A4D8: main (a.cpp:43)
Address 0x10f120 is 8 bytes inside data symbol "cv"
----------------------------------------------------------------
Possible data race during read of size 4 at 0x10F0F8 by thread #2
Locks held: none
at 0x52E41DB: __pthread_mutex_cond_lock (pthread_mutex_lock.c:94)
by 0x52E0933: __pthread_cond_wait_common (pthread_cond_wait.c:616)
by 0x52E0933: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
by 0x10AD44: void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (std_thread.h:259)
by 0x10AD14: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (std_thread.h:266)
by 0x10AC78: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (std_thread.h:211)
by 0x50FD252: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
This conflicts with a previous write of size 4 by thread #1
Locks held: none
at 0x52E696C: __pthread_mutex_unlock_usercnt (pthread_mutex_unlock.c:62)
by 0x52E08AD: __pthread_cond_wait_common (pthread_cond_wait.c:419)
by 0x52E08AD: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A60C: void std::condition_variable::wait<main::$_1>(std::unique_lock<std::mutex>&, main::$_1) (condition_variable:103)
by 0x10A4FD: main (a.cpp:48)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x10F0F8 by thread #2
Locks held: none
at 0x52E41EE: __pthread_mutex_cond_lock (pthread_mutex_lock.c:170)
by 0x52E0933: __pthread_cond_wait_common (pthread_cond_wait.c:616)
by 0x52E0933: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:627)
by 0x4E1390B: pthread_cond_wait_WRK (hg_intercepts.c:1291)
by 0x4E14EAA: pthread_cond_wait@* (hg_intercepts.c:1318)
by 0x10A44C: void std::condition_variable::wait<worker_thread()::$_0>(std::unique_lock<std::mutex>&, worker_thread()::$_0) (condition_variable:103)
by 0x10A36B: worker_thread() (a.cpp:16)
by 0x10ADD6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
by 0x10AD6C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
by 0x10AD44: void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (std_thread.h:259)
by 0x10AD14: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (std_thread.h:266)
by 0x10AC78: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (std_thread.h:211)
by 0x50FD252: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
This conflicts with a previous write of size 4 by thread #1
Locks held: none
...
by 0x10A4FD: main (a.cpp:48)
Address 0x10f0f8 is 8 bytes inside data symbol "m"
Worker thread is processing data
Worker thread signals data processing completed
----------------------------------------------------------------
Thread #2: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
...
by 0x10A3D9: worker_thread() (a.cpp:29)
----------------------------------------------------------------
Possible data race during write of size 8 at 0x10F120 by thread #2
Locks held: none
...
by 0x10A3D9: worker_thread() (a.cpp:29)
...
This conflicts with a previous read of size 8 by thread #1
Locks held: none
...
by 0x10A4FD: main (a.cpp:48)
Address 0x10f120 is 8 bytes inside data symbol "cv"
----------------------------------------------------------------
Possible data race during read of size 8 at 0x10F120 by thread #1
Locks held: none
...
by 0x10A4FD: main (a.cpp:48)
This conflicts with a previous write of size 8 by thread #2
Locks held: none
...
Address 0x10f120 is 8 bytes inside data symbol "cv"
Back in main(), data = Example data after processing
Use --history-level=approx or =none to gain increased speed, at
the cost of reduced accuracy of conflicting-access information
For lists of detected and suppressed errors, rerun with: -s
ERROR SUMMARY: 19 errors from 14 contexts (suppressed: 0 from 0)
std::thread
(即 POSIX 线程、Boost.Thread,...)?
--suppressions
选项一起使用(以防它报告的 18 个错误是误报)?