Гонка данных при передаче указателя на std :: thread - PullRequest
0 голосов
/ 31 марта 2020

Я озадачен отчетом о дезинфекции потоков, который появляется как для G CC 8, так и для Clang 9 (другие я не пробовал). Существует структура Bar со следующим кодом:

struct Bar {

    Bar(bool create_foo) {
        ... 
        if (create_foo) {
            mFoo = new Foo();
            mFooThread = std::thread(&Foo::Run, mFoo); // This is a Data Race?!?!?!?
            mOther->setFoo(mFoo);
        }
        ... 
    }

    ~Bar() {
        if (mFooThread.joinable()) mFooThread.join();
    }

    Foo * mFoo;
    std::thread mFooThread;
    Other * mOther;
}

Запуск средства очистки потока в Ubuntu 18.04 с обоими компиляторами говорит, что строка создания потока (см. Комментарий выше) является гонкой данных. Единственное другое место, где используется этот поток (mFooThread), - деструктор Bar.

Чтобы дать больше подробностей ... дезинфицирующее средство потока сообщает 18 ошибок. 2 из них, похоже, не имеют никакого отношения к текущему проекту. Остальные все указывают на эту линию. Смущает то, что ошибки, похоже, не указывают ни на какую другую часть кодовой базы. Кажется, они просто указывают на эту линию. В программе создается только один объект Bar, что заставляет меня задуматься, почему я вижу 16 ошибок.

2 ошибки, которые, я считаю, не связаны с проектом:

Lock-order-inversion (potential deadlock) (pid=3891)
Mutex M2925 acquired here while holding mutex M2921 in main thread:
pthread_mutex_lock
CPLAcquireMutex
Mutex M2921 acquired here while holding mutex M2925 in main thread:
pthread_mutex_lock
CPLCreateOrAcquireMutexEx

Lock-order-inversion (potential deadlock) (pid=3891)
Mutex M2922 acquired here while holding mutex M2921 in main thread:
pthread_mutex_lock
CPLAcquireMutex
Mutex M2921 acquired here while holding mutex M2922 in main thread:
pthread_mutex_lock
CPLCreateOrAcquireMutexEx

Для справки, это проект Cmake, который я не создавал, но, похоже, в нем есть некоторые Проблемы с потоками, так как пользователи сообщают, что программа случайно зависает. Я включил средство очистки потока следующим образом:

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=${sanitize}")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=${sanitize}")

РЕДАКТИРОВАТЬ:

Ниже приведен вывод TSAN для одного из предупреждений о гонке данных. Все они очень похожи:

Write of size 8 at 0x7b5000018500 by thread T29:
memset
g_slice_alloc0
Previous write of size 8 at 0x7b5000018500 by thread T15 (mutexes: write M3854):
posix_memalign
(libglib-2.0.so.0+0x690e6)
void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&)
std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&)
decltype(std::__invoke(_S_declval<0ul>(), _S_declval<1ul>())) std::thread::_Invoker<std::tuple>::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>)
std::thread::_Invoker<std::tuple>::operator()()
std::thread::_State_impl<std::thread::_Invoker>::_M_run()
(libstdc++.so.6+0xbd6de)

Location is heap block of size 496 at 0x7b5000018400 allocated by thread T15:
posix_memalign
(libglib-2.0.so.0+0x690e6)
void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&)
std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&)
decltype(std::__invoke(_S_declval<0ul>(), _S_declval<1ul>())) std::thread::_Invoker<std::tuple>::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>)
std::thread::_Invoker<std::tuple>::operator()()
std::thread::_State_impl<std::thread::_Invoker>::_M_run()
(libstdc++.so.6+0xbd6de)

Mutex M3854 (0x7b0c00536f70) created at:
pthread_mutex_init
(libglib-2.0.so.0+0x91e2c)
void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&)
std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&)
decltype(std::__invoke(_S_declval<0ul>(), _S_declval<1ul>())) std::thread::_Invoker<std::tuple>::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>)
std::thread::_Invoker<std::tuple>::operator()()
std::thread::_State_impl<std::thread::_Invoker>::_M_run()
(libstdc++.so.6+0xbd6de)

Thread T29 'gdbus' (tid=5438, running) created by thread T15 at:
pthread_create
(libglib-2.0.so.0+0x9240f)
void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&)
std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&)
decltype(std::__invoke(_S_declval<0ul>(), _S_declval<1ul>())) std::thread::_Invoker<std::tuple>::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>)
std::thread::_Invoker<std::tuple>::operator()()
std::thread::_State_impl<std::thread::_Invoker>::_M_run()
(libstdc++.so.6+0xbd6de)

Thread T15 (tid=5423, running) created by main thread at:
pthread_create
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete>, void (*)())
Bar::Bar(bool)
main
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...