2017-02-11 5 views
1

Согласно C++ documentation, блок управления shared_ptr является потокобезопасным. т.е. оператор = или сброс доступны для нескольких потоков без явной блокировки.
Но я вижу странное поведение; общий объект дважды освобождается от времени:Неисправность потока указателей с открытым кодом C++ 11 нарушена?

#include <iostream> 
#include <memory> 
#include <unistd.h> 

using namespace std; 

class MyClass { 
public: 
    MyClass(string x) : name(x) {cout<<"C->"<<name<<endl;}; 
    ~MyClass() {cerr<<"D->"<<name<<endl;}; 
    string name; 
}; 

shared_ptr<MyClass> a; 

void* tfunc(void*) { 
    while(1){ 
    { 
     shared_ptr<MyClass> s = a; 
     usleep(5); 
    } 
    } 
} 

int main(void) { 
    pthread_t threadid; 
    a = make_shared<MyClass>("a"); 
    if(pthread_create(&threadid, NULL, tfunc, NULL)) { 
     cout<<"pthread_create error"<<endl; 
     return -1; 
    } 
    while(1){ 
     usleep(5); 
     a = make_shared<MyClass>("b"); 
    } 

    pthread_join(threadid, NULL); 
    return 0; 
} 

Вот Адрес дезинфицирующее выход:

==28588==ERROR: AddressSanitizer: heap-use-after-free on address 0xb33a7ad4 at pc 0x080490c4 bp 0xb54ff1d8 sp 0xb54ff1c8 
WRITE of size 4 at 0xb33a7ad4 thread T1 
    #0 0x80490c3 in __exchange_and_add /usr/include/c++/6/ext/atomicity.h:49 
    #1 0x80491ed in __exchange_and_add_dispatch /usr/include/c++/6/ext/atomicity.h:82 
    #2 0x8049a9e in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/6/bits/shared_ptr_base.h:147 
    #3 0x80498a3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/6/bits/shared_ptr_base.h:662 
    #4 0x804977e in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/6/bits/shared_ptr_base.h:928 
    #5 0x8049797 in std::shared_ptr<MyClass>::~shared_ptr() /usr/include/c++/6/bits/shared_ptr.h:93 
    #6 0x80492d7 in tfunc(void*) /tmp/main.cpp:19 
    #7 0xb7248c4e (/usr/lib/i386-linux-gnu/libasan.so.3+0x26c4e) 
    #8 0xb6ea5304 in start_thread (/lib/i386-linux-gnu/libpthread.so.0+0x6304) 
    #9 0xb6fb347d in __clone (/lib/i386-linux-gnu/libc.so.6+0xe947d) 

0xb33a7ad4 is located 4 bytes inside of 36-byte region [0xb33a7ad0,0xb33a7af4) 
freed by thread T0 here: 
    #0 0xb72e7174 in operator delete(void*) (/usr/lib/i386-linux-gnu/libasan.so.3+0xc5174) 
    #1 0x804ace0 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> >::deallocate(std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>*, unsigned int) /usr/include/c++/6/ext/new_allocator.h:110 
    #2 0x804ab07 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> > >::deallocate(std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> >&, std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>*, unsigned int) /usr/include/c++/6/bits/alloc_traits.h:442 
    #3 0x804a818 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> > >::~__allocated_ptr() /usr/include/c++/6/bits/allocated_ptr.h:73 
    #4 0x804b0aa in std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>::_M_destroy() /usr/include/c++/6/bits/shared_ptr_base.h:537 
    #5 0x8049bbe in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/6/bits/shared_ptr_base.h:166 
    #6 0x80498a3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/6/bits/shared_ptr_base.h:662 
    #7 0x804977e in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/6/bits/shared_ptr_base.h:928 
    #8 0x8049cd4 in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::operator=(std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>&&) /usr/include/c++/6/bits/shared_ptr_base.h:1003 
    #9 0x8049a7c in std::shared_ptr<MyClass>::operator=(std::shared_ptr<MyClass>&&) /usr/include/c++/6/bits/shared_ptr.h:294 
    #10 0x8049430 in main /tmp/main.cpp:35 
    #11 0xb6ee2275 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18275) 

НКУ-6,2 и LLVM-3,9 показать такое же поведение. Это ошибка в библиотеке C++?

ответ

1

= и reset не являются потокобезопасными. Нужны shared_ptr перегрузки функций std::atomic_....

«Блок управления потокобезопасно» означает, что вы можете использовать = и reset в нескольких потоках (но каждый поток использует отдельную shared_ptr), даже если все shared_ptr объектов копий друг.

+0

'std :: mutex' может обеспечить лучшее решение, чем' std :: atomic '. – Potatoswatter

+0

Что это значит? если sptr1 = sptr2 = make_shared («b»), сколько блоков управления будет там? Только один .. правильно? Если это не потокобезопасно, в чем смысл использования общего указателя. Разве это не превратит жизнь разработчика в кошмар? В случае обычных указателей разработчик может управлять уничтожением управляемого объекта. Но shared_ptr делает это неопределенным. –

+0

@VinodKd Да, будет только один. Но вам нужно скопировать 'shared_ptr' ** перед ** началом потока (или передать как аргумент), а не ** после **. – cshu

Смежные вопросы