gpt4 book ai didi

c++ - 线程访问静态映射时出现段错误

转载 作者:行者123 更新时间:2023-12-02 10:31:00 24 4
gpt4 key购买 nike

考虑以下代码片段:

myEnum stringToEnum(const std::string& enumString) {
static const std::unordered_map<std::string, myEnum> conversionMap = {
{"enumA", myEnum::enumA},
{"enumB", myEnum::enumB},
{"enumC", myEnum::enumC}};

if(conversionMap.count(enumString) == 0) {
// Return some default value
}
return conversionMap.at(enumString);
}


void threadedFcn() {
// Do some things
for (int i = 0; i < someNumber; ++i) {
// Do some more things
auto myEnum = stringToEnum(myString);
// Do even more stuff
}
}

int main() {
threadedFcn(); // No problem
std::thread(threadedFcn).join(); // No problem
std::thread(threadedFcn).detach(); // Seg fault
}

关于此的一些事情:
  • 如果删除对count的调用,则不会出现段错误。看起来是由某种原因造成的。
  • 它仅在Linux Debian 9上发生(我也是在Windows 10和Mac上构建的)。
  • 如果在detach调用后添加类似std::this_thread::sleep_for(std::chrono::milliseconds(2000));的内容,则不会出现段错误。
  • 如果我将conversionMap设为非静态,则不会出现段错误。

  • 我不知道确切的问题是什么,但这与在分离线程完成之前退出主线程有关。

    最佳答案

    正如Slava正确地说的那样,问题在于您正在让main返回,而另一个线程正在运行。

    main返回最终会调用exit,它会通过所有已注册的atexit处理程序。

    当使用libstdc++(以及可能的大多数其他C++运行时实现)时,任何已构造的静态C++对象都会使用atexit注册其析构函数,因此在析构函数触发后,您的分离线程正在访问已破坏的conversionMap对象,其结果可预测。

    您可以使用Address Sanitizer(-fsanitize=address)观察到此情况,该报告报告:

    =================================================================
    ==87625==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000010 at pc 0x563122b9c6c5 bp 0x7fc54eafea20 sp 0x7fc54eafea18
    READ of size 8 at 0x603000000010 thread T2
    #0 0x563122b9c6c4 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_M_bucket_begin(unsigned long) const /usr/include/c++/9/bits/hashtable.h:943
    #1 0x563122b9bcf2 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::count(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const /usr/include/c++/9/bits/hashtable.h:1451
    #2 0x563122b9b76e in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, myEnum, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::ba
    sic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > >::count(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const /usr/include/c++/9/bits/unordered_map.h:939
    #3 0x563122b9a793 in stringToEnum(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /tmp/t.cc:16
    #4 0x563122b9aa9c in threadedFcn() /tmp/t.cc:27
    #5 0x563122b9f71e in void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/include/c++/9/bits/invoke.h:60
    #6 0x563122b9f681 in std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/include/c++/9/bits/invoke.h:95
    #7 0x563122b9f5cb in void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/9/thread:244
    #8 0x563122b9f56c in std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/include/c++/9/thread:251
    #9 0x563122b9f4ed in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/include/c++/9/thread:195
    #10 0x7fc552301baf (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xcebaf)
    #11 0x7fc55202bf26 in start_thread /build/glibc-M65Gwz/glibc-2.30/nptl/pthread_create.c:479
    #12 0x7fc5521532ee in __clone (/lib/x86_64-linux-gnu/libc.so.6+0xfd2ee)

    0x603000000010 is located 0 bytes inside of 24-byte region [0x603000000010,0x603000000028)
    freed by thread T0 here:
    #0 0x7fc552509f97 in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x109f97)
    #1 0x563122b9e5fb in __gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::deallocate(std::__detail::_Hash_node_base**, unsigned long) /usr/include/c++/9/ext/new_allocator.h:128
    #2 0x563122b9dbf5 in std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*> >::deallocate(std::allocator<std::__detail::_Hash_node_base*>&, std::__detail::_Hash_node_base**, unsigned long) /usr/include/c++/9/bits/alloc_traits.h:470
    #3 0x563122b9d0cc in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, true> > >::_M_deallocate_buckets(std::__detail::_Hash_node_base**, unsigned long) /usr/include/c++/9/bits/hashtable_policy.h:2148
    #4 0x563122b9c5d3 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_M_deallocate_buckets(std::__detail::_Hash_node_base**, unsigned long) /usr/include/c++/9/bits/hashtable.h:370
    #5 0x563122b9bc99 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_M_deallocate_buckets() /usr/include/c++/9/bits/hashtable.h:375
    #6 0x563122b9b73b in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::~_Hashtable() /usr/include/c++/9/bits/hashtable.h:1353
    #7 0x563122b9b4ff in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, myEnum, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::ba
    sic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > >::~unordered_map() /usr/include/c++/9/bits/unordered_map.h:102
    #8 0x7fc552093e26 in __run_exit_handlers /build/glibc-M65Gwz/glibc-2.30/stdlib/exit.c:108

    previously allocated by thread T0 here:
    #0 0x7fc55250919f in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10919f)
    #1 0x563122b9e828 in __gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::allocate(unsigned long, void const*) /usr/include/c++/9/ext/new_allocator.h:114
    #2 0x563122b9defc in std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*> >::allocate(std::allocator<std::__detail::_Hash_node_base*>&, unsigned long) /usr/include/c++/9/bits/alloc_traits.h:444
    #3 0x563122b9d6d4 in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, true> > >::_M_allocate_buckets(unsigned long) /usr/include/c++/9/bits/hashtable_policy.h:2134
    #4 0x563122b9ce5b in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_M_allocate_buckets(unsigned long) /usr/include/c++/9/bits/hashtable.h:361
    #5 0x563122b9c3db in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_Hashtable<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> const*>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> const*, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> const*, unsigned l
    ong, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__detail::_Mod_range_hashing const&, std::__detail::_Default_ranged_hash const&, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__detail::_Select1st const&, std::allocator<std::pair<std::__cxx
    11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > const&) /usr/include/c++/9/bits/hashtable.h:989
    #6 0x563122b9bab5 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, std::__detail
    ::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>
    >::_Hashtable(std::initializer_list<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&,
    std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > const&) /usr/include/c++/9/bits/hashtable.h:466
    #7 0x563122b9b6a3 in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, myEnum, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::ba
    sic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > >::unordered_map(std::initializer_list<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::equal_to<std::__
    cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, myEnum> > const&) /usr/include/c++/9/bits/unordered_map.h:231
    #8 0x563122b9a678 in stringToEnum(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /tmp/t.cc:14
    #9 0x563122b9aa9c in threadedFcn() /tmp/t.cc:27
    #10 0x563122b9ac0f in main /tmp/t.cc:33
    #11 0x7fc55207ce0a in __libc_start_main ../csu/libc-start.c:308

    Thread T2 created by T0 here:
    #0 0x7fc5524399b2 in pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x399b2)
    #1 0x7fc552301e24 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xcee24)
    #2 0x563122b9ac75 in main /tmp/t.cc:35
    #3 0x7fc55207ce0a in __libc_start_main ../csu/libc-start.c:308

    更新:

    I guess an easy fix is to just make my variable not-static (functionally it will be the same but with an obvious performance hit).



    有一个简单的方法可以避免在每次调用时都必须构造一个新的 unordered_map,同时还可以避免全局破坏问题:使用静态指针:

    myEnum stringToEnum(const std::string& enumString) {
    static const auto *conversionMap =
    new std::unordered_map<std::string, myEnum>{
    {"enumA", myEnum::enumA},
    {"enumB", myEnum::enumB},
    {"enumC", myEnum::enumC}
    };

    if (conversionMap->count(enumString) == 0) {
    // Return some default value
    }
    return conversionMap->at(enumString);
    }

    关于c++ - 线程访问静态映射时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62292411/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com