适用于从多个线程调用其自己的成员功能的类适当锁定。 (我需要锁定访问“指针”的“指标?)
我正在编写一个多线程应用程序,目前有一个类,可以催生线程,然后从这些线程中调用其自己的成员函数。我认为,只要成员函数本身不使用任何共享资源,就可以了,但是当我使用valgrind
使用- tool = helgrind
选项时数据竞赛和其他与线程相关的问题。
foo_main.cpp:
#include <iostream>
#include <mutex>
#include <thread>
class Foo final
{
public:
void DoSomething() const
{
std::thread t1([&] {
// Do I need to lock before accessing "this"?
// std::lock_guard<std::mutex> lock(m_mutex);
this->Print();
});
std::thread t2([&] {
// Do I need to lock before accessing "this"?
// std::lock_guard<std::mutex> lock(m_mutex);
this->Print();
});
t1.join();
t2.join();
}
private:
void Print() const
{
std::lock_guard<std::mutex> lock(m_mutex);
std::cout << "TEST" << std::endl;
}
mutable std::mutex m_mutex;
};
int main()
{
Foo foo;
foo.DoSomething();
}
这是Valgrind的输出:
valgrind --tool=helgrind ./foo
==27751== Helgrind, a thread error detector
==27751== Copyright (C) 2007-2017, and GNU GPL'd, by OpenWorks LLP et al.
==27751== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==27751== Command: ./foo
==27751==
TEST
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #1 is the program's root thread
==27751==
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #2 was created
==27751== at 0x7848ACE: clone (in /usr/lib64/libc-2.17.so)
==27751== by 0x5051059: do_clone.constprop.4 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x5052569: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x4C355BE: pthread_create_WRK (hg_intercepts.c:445)
==27751== by 0x4C36A9B: pthread_create@* (hg_intercepts.c:478)
==27751== by 0x531B596: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x401C94: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401C94: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during write of size 8 at 0xA6A6E18 by thread #1
==27751== Locks held: none
==27751== at 0x4018FA: ~_Impl_base (thread:97)
==27751== by 0x4018FA: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >::~_Impl() (thread:107)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (new_allocator.h:124)
==27751== by 0x401508: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:281)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:405)
==27751== by 0x401508: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401CD0: _M_release (shared_ptr_base.h:144)
==27751== by 0x401CD0: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401CD0: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401CD0: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401CD0: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401CD0: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous read of size 8 by thread #2
==27751== Locks held: none
==27751== at 0x531B316: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e18 is 24 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401BEF: allocate (new_allocator.h:104)
==27751== by 0x401BEF: allocate (alloc_traits.h:351)
==27751== by 0x401BEF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:499)
==27751== by 0x401BEF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:957)
==27751== by 0x401BEF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:316)
==27751== by 0x401BEF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:598)
==27751== by 0x401BEF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:614)
==27751== by 0x401BEF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (thread:193)
==27751== by 0x401BEF: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401BEF: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during read of size 8 at 0xA6A6E28 by thread #1
==27751== Locks held: none
==27751== at 0x4018FD: ~__shared_count (shared_ptr_base.h:545)
==27751== by 0x4018FD: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x4018FD: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x4018FD: ~_Impl_base (thread:97)
==27751== by 0x4018FD: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >::~_Impl() (thread:107)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (new_allocator.h:124)
==27751== by 0x401508: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:281)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:405)
==27751== by 0x401508: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401CD0: _M_release (shared_ptr_base.h:144)
==27751== by 0x401CD0: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401CD0: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401CD0: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401CD0: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401CD0: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous write of size 8 by thread #2
==27751== Locks held: none
==27751== at 0x531B325: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e28 is 40 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401BEF: allocate (new_allocator.h:104)
==27751== by 0x401BEF: allocate (alloc_traits.h:351)
==27751== by 0x401BEF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:499)
==27751== by 0x401BEF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:957)
==27751== by 0x401BEF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:316)
==27751== by 0x401BEF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:598)
==27751== by 0x401BEF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:614)
==27751== by 0x401BEF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (thread:193)
==27751== by 0x401BEF: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401BEF: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
TEST
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #3 was created
==27751== at 0x7848ACE: clone (in /usr/lib64/libc-2.17.so)
==27751== by 0x5051059: do_clone.constprop.4 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x5052569: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x4C355BE: pthread_create_WRK (hg_intercepts.c:445)
==27751== by 0x4C36A9B: pthread_create@* (hg_intercepts.c:478)
==27751== by 0x531B596: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x401E96: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401E96: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during write of size 8 at 0xA6A6E18 by thread #1
==27751== Locks held: none
==27751== at 0x40187C: ~_Impl_base (thread:97)
==27751== by 0x40187C: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >::~_Impl() (thread:107)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (new_allocator.h:124)
==27751== by 0x4014E6: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:281)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:405)
==27751== by 0x4014E6: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401ED5: _M_release (shared_ptr_base.h:144)
==27751== by 0x401ED5: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401ED5: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401ED5: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401ED5: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401ED5: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous read of size 8 by thread #3
==27751== Locks held: none
==27751== at 0x531B316: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e18 is 24 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401DAF: allocate (new_allocator.h:104)
==27751== by 0x401DAF: allocate (alloc_traits.h:351)
==27751== by 0x401DAF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:499)
==27751== by 0x401DAF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:957)
==27751== by 0x401DAF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:316)
==27751== by 0x401DAF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:598)
==27751== by 0x401DAF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:614)
==27751== by 0x401DAF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (thread:193)
==27751== by 0x401DAF: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401DAF: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during read of size 8 at 0xA6A6E28 by thread #1
==27751== Locks held: none
==27751== at 0x40187F: ~__shared_count (shared_ptr_base.h:545)
==27751== by 0x40187F: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x40187F: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x40187F: ~_Impl_base (thread:97)
==27751== by 0x40187F: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >::~_Impl() (thread:107)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (new_allocator.h:124)
==27751== by 0x4014E6: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:281)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:405)
==27751== by 0x4014E6: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401ED5: _M_release (shared_ptr_base.h:144)
==27751== by 0x401ED5: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401ED5: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401ED5: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401ED5: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401ED5: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous write of size 8 by thread #3
==27751== Locks held: none
==27751== at 0x531B325: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e28 is 40 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401DAF: allocate (new_allocator.h:104)
==27751== by 0x401DAF: allocate (alloc_traits.h:351)
==27751== by 0x401DAF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:499)
==27751== by 0x401DAF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:957)
==27751== by 0x401DAF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:316)
==27751== by 0x401DAF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:598)
==27751== by 0x401DAF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:614)
==27751== by 0x401DAF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (thread:193)
==27751== by 0x401DAF: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401DAF: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751==
==27751== Use --history-level=approx or =none to gain increased speed, at
==27751== the cost of reduced accuracy of conflicting-access information
==27751== For lists of detected and suppressed errors, rerun with: -s
==27751== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 9 from 8)
从多个线程访问成员函数时,我总是需要锁定在尝试通过“此”指针访问访问之前?由于它是const
成员函数,因此不会修改对象本身。
在实际应用程序中,我正在处理线程调用的成员函数的工作量很多,因此将代码从成员函数中移出并在我使用的任何地方复制它并不是一个选择。但是,锁定甚至在调用该函数之前就会提出问题,因为可以同时完成函数中的许多内容,并防止不使用共享资源同时运行的功能的部分会大大减慢应用程序的速度。
I am working on writing a multithreaded application and it currently has a class that spawns threads and then calls its own member functions from within those threads. I thought this would be fine as long as the member function itself doesn't use any shared resources, but when I ran valgrind
with the --tool=helgrind
option to detect data races and other thread related issues it complains.
foo_main.cpp:
#include <iostream>
#include <mutex>
#include <thread>
class Foo final
{
public:
void DoSomething() const
{
std::thread t1([&] {
// Do I need to lock before accessing "this"?
// std::lock_guard<std::mutex> lock(m_mutex);
this->Print();
});
std::thread t2([&] {
// Do I need to lock before accessing "this"?
// std::lock_guard<std::mutex> lock(m_mutex);
this->Print();
});
t1.join();
t2.join();
}
private:
void Print() const
{
std::lock_guard<std::mutex> lock(m_mutex);
std::cout << "TEST" << std::endl;
}
mutable std::mutex m_mutex;
};
int main()
{
Foo foo;
foo.DoSomething();
}
Here is the output from valgrind:
valgrind --tool=helgrind ./foo
==27751== Helgrind, a thread error detector
==27751== Copyright (C) 2007-2017, and GNU GPL'd, by OpenWorks LLP et al.
==27751== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==27751== Command: ./foo
==27751==
TEST
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #1 is the program's root thread
==27751==
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #2 was created
==27751== at 0x7848ACE: clone (in /usr/lib64/libc-2.17.so)
==27751== by 0x5051059: do_clone.constprop.4 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x5052569: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x4C355BE: pthread_create_WRK (hg_intercepts.c:445)
==27751== by 0x4C36A9B: pthread_create@* (hg_intercepts.c:478)
==27751== by 0x531B596: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x401C94: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401C94: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during write of size 8 at 0xA6A6E18 by thread #1
==27751== Locks held: none
==27751== at 0x4018FA: ~_Impl_base (thread:97)
==27751== by 0x4018FA: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >::~_Impl() (thread:107)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (new_allocator.h:124)
==27751== by 0x401508: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:281)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:405)
==27751== by 0x401508: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401CD0: _M_release (shared_ptr_base.h:144)
==27751== by 0x401CD0: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401CD0: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401CD0: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401CD0: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401CD0: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous read of size 8 by thread #2
==27751== Locks held: none
==27751== at 0x531B316: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e18 is 24 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401BEF: allocate (new_allocator.h:104)
==27751== by 0x401BEF: allocate (alloc_traits.h:351)
==27751== by 0x401BEF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:499)
==27751== by 0x401BEF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:957)
==27751== by 0x401BEF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:316)
==27751== by 0x401BEF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:598)
==27751== by 0x401BEF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:614)
==27751== by 0x401BEF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (thread:193)
==27751== by 0x401BEF: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401BEF: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during read of size 8 at 0xA6A6E28 by thread #1
==27751== Locks held: none
==27751== at 0x4018FD: ~__shared_count (shared_ptr_base.h:545)
==27751== by 0x4018FD: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x4018FD: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x4018FD: ~_Impl_base (thread:97)
==27751== by 0x4018FD: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >::~_Impl() (thread:107)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (new_allocator.h:124)
==27751== by 0x401508: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:281)
==27751== by 0x401508: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > > (alloc_traits.h:405)
==27751== by 0x401508: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#1} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401CD0: _M_release (shared_ptr_base.h:144)
==27751== by 0x401CD0: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401CD0: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401CD0: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401CD0: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401CD0: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous write of size 8 by thread #2
==27751== Locks held: none
==27751== at 0x531B325: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e28 is 40 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401BEF: allocate (new_allocator.h:104)
==27751== by 0x401BEF: allocate (alloc_traits.h:351)
==27751== by 0x401BEF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:499)
==27751== by 0x401BEF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr_base.h:957)
==27751== by 0x401BEF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:316)
==27751== by 0x401BEF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:598)
==27751== by 0x401BEF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (shared_ptr.h:614)
==27751== by 0x401BEF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda0()> > (thread:193)
==27751== by 0x401BEF: thread<Foo::DoSomething() const::__lambda0> (thread:135)
==27751== by 0x401BEF: Foo::DoSomething() const (foo_main.cpp:14)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
TEST
==27751== ---Thread-Announcement------------------------------------------
==27751==
==27751== Thread #3 was created
==27751== at 0x7848ACE: clone (in /usr/lib64/libc-2.17.so)
==27751== by 0x5051059: do_clone.constprop.4 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x5052569: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x4C355BE: pthread_create_WRK (hg_intercepts.c:445)
==27751== by 0x4C36A9B: pthread_create@* (hg_intercepts.c:478)
==27751== by 0x531B596: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x401E96: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401E96: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during write of size 8 at 0xA6A6E18 by thread #1
==27751== Locks held: none
==27751== at 0x40187C: ~_Impl_base (thread:97)
==27751== by 0x40187C: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >::~_Impl() (thread:107)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (new_allocator.h:124)
==27751== by 0x4014E6: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:281)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:405)
==27751== by 0x4014E6: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401ED5: _M_release (shared_ptr_base.h:144)
==27751== by 0x401ED5: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401ED5: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401ED5: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401ED5: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401ED5: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous read of size 8 by thread #3
==27751== Locks held: none
==27751== at 0x531B316: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e18 is 24 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401DAF: allocate (new_allocator.h:104)
==27751== by 0x401DAF: allocate (alloc_traits.h:351)
==27751== by 0x401DAF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:499)
==27751== by 0x401DAF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:957)
==27751== by 0x401DAF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:316)
==27751== by 0x401DAF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:598)
==27751== by 0x401DAF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:614)
==27751== by 0x401DAF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (thread:193)
==27751== by 0x401DAF: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401DAF: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751== ----------------------------------------------------------------
==27751==
==27751== Possible data race during read of size 8 at 0xA6A6E28 by thread #1
==27751== Locks held: none
==27751== at 0x40187F: ~__shared_count (shared_ptr_base.h:545)
==27751== by 0x40187F: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x40187F: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x40187F: ~_Impl_base (thread:97)
==27751== by 0x40187F: std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >::~_Impl() (thread:107)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (new_allocator.h:124)
==27751== by 0x4014E6: _S_destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:281)
==27751== by 0x4014E6: destroy<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > > (alloc_traits.h:405)
==27751== by 0x4014E6: std::_Sp_counted_ptr_inplace<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::{lambda()#2} ()> > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:407)
==27751== by 0x401ED5: _M_release (shared_ptr_base.h:144)
==27751== by 0x401ED5: ~__shared_count (shared_ptr_base.h:546)
==27751== by 0x401ED5: ~__shared_ptr (shared_ptr_base.h:781)
==27751== by 0x401ED5: ~shared_ptr (shared_ptr.h:93)
==27751== by 0x401ED5: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401ED5: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751==
==27751== This conflicts with a previous write of size 8 by thread #3
==27751== Locks held: none
==27751== at 0x531B325: ??? (in /usr/lib64/libstdc++.so.6.0.19)
==27751== by 0x4C357B2: mythread_wrapper (hg_intercepts.c:406)
==27751== by 0x5051EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
==27751== by 0x7848B0C: clone (in /usr/lib64/libc-2.17.so)
==27751== Address 0xa6a6e28 is 40 bytes inside a block of size 56 alloc'd
==27751== at 0x4C2D7B8: operator new(unsigned long) (vg_replace_malloc.c:422)
==27751== by 0x401DAF: allocate (new_allocator.h:104)
==27751== by 0x401DAF: allocate (alloc_traits.h:351)
==27751== by 0x401DAF: __shared_count<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:499)
==27751== by 0x401DAF: __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr_base.h:957)
==27751== by 0x401DAF: shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:316)
==27751== by 0x401DAF: allocate_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:598)
==27751== by 0x401DAF: make_shared<std::thread::_Impl<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> >, std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (shared_ptr.h:614)
==27751== by 0x401DAF: _M_make_routine<std::_Bind_simple<Foo::DoSomething() const::__lambda1()> > (thread:193)
==27751== by 0x401DAF: thread<Foo::DoSomething() const::__lambda1> (thread:135)
==27751== by 0x401DAF: Foo::DoSomething() const (foo_main.cpp:20)
==27751== by 0x401480: main (foo_main.cpp:38)
==27751== Block was alloc'd by thread #1
==27751==
==27751==
==27751== Use --history-level=approx or =none to gain increased speed, at
==27751== the cost of reduced accuracy of conflicting-access information
==27751== For lists of detected and suppressed errors, rerun with: -s
==27751== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 9 from 8)
When accessing a member function from multiple threads do I always need to lock BEFORE attempting access through the "this" pointer? Since it is a const
member function it won't modify the object itself so I wouldn't think there would be an issue but valgrind
is still giving me a lot of warnings.
In the real application I am working on the member function being called by the threads does quite a lot, so moving the code out of the member function and copying it everywhere I use it isn't really an option. But locking before even calling the function poses a problem because a lot of what is in the function could be done concurrently and preventing the portions of the function that don't use shared resources from running concurrently would significantly slow down the application.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这确实有点像libstdc ++中的旧错误。这是我得到的输出。
看起来像是对内存的原始读物。我没有libstdc ++ debuginfo,所以我不能说“ ???”在哪里是。呼叫堆位于新线程中,所以我想是libstdc ++准备调用lambda。
回到主机上,对于std ::线程创建和关闭,我看到libstc ++已从使用std :: shared_ptr转换为std :: solution_ptr。
我很确定libstdc ++代码是
指针:
这是实现std ::线程内部状态实现的模板类。
This does look a bit like an old bug in libstdc++. This is the output that I get.
That looks like a raw read of memory. I don't have libstdc++ debuginfo so I can't tell where the '???' is. The callstack is in the new thread so I guess it's libstdc++ preparing to call the lambda.
Back in main, for the std::thread creation and shutdown, I see that libstc++ has switched from using std::shared_ptr to std::unique_ptr.
I'm pretty sure that the libstdc++ code is
The pointer is:
That's the template class implementing the std::thread internal state implementation.