繁体   English   中英

调试线程池中 std::string 的使用 C++

[英]Debugging the use of std::string in a thread pool C++

我正在尝试弄清楚多线程 - 我对它很陌生。 我正在使用在这里找到的 thread_pool 类型。 对于足够大的N ,以下代码段错误。 你们能帮我理解为什么以及如何解决吗?


#include "thread_pool.hpp"
#include <thread>
#include <iostream>

static std::mutex mtx;
void printString(const std::string &s) {
    std::lock_guard lock(mtx);
    std::hash<std::thread::id> tid{};
    auto id = tid(std::this_thread::get_id()) % 16;
    std::cout << "thread: " << id << " " << s << std::endl;
}

TEST(test, t) {
    thread_pool pool(16);
    int N = 1000000;
    std::vector<std::string> v(N);
    for (int i = 0; i < N; i++) {
        v[i] = std::to_string(i);
    }
    for (auto &s: v) {
        pool.push_task([&s]() {
            printString(s);
        });
    }

}

这是线程清理程序 output(请注意 ===> 注释,我将您引导到适当的行“):

SEGV on unknown address 0x000117fbdee8 (pc 0x000102fa35b6 bp 0x7e8000186b50 sp 0x7e8000186b30 T257195)
0x102fa35b6 std::basic_string::__get_short_size const string:1514 
0x102fa3321 std::basic_string::size const string:970 
0x102f939e6 std::operator<<<…> ostream:1056 
0x102f9380b printString RoadRunnerMapTests.cpp:37   // ==> this line: void printString(const std::string &s) {
0x102fabbd5 $_0::operator() const RoadRunnerMapTests.cpp:49     // ===> this line: v[i] = std::to_string(i);
0x102fabb3d (test_cxx_api_RoadRunnerMapTests:x86_64+0x10001eb3d) type_traits:3694 
0x102fabaad std::__invoke_void_return_wrapper::__call<…> __functional_base:348 
0x102faba5d std::__function::__alloc_func::operator() functional:1558 
0x102fa9669 std::__function::__func::operator() functional:1732 
0x102f9d383 std::__function::__value_func::operator() const functional:1885 
0x102f9c055 std::function::operator() const functional:2560 
0x102f9bc29 thread_pool::worker thread_pool.hpp:389  // ==> [this](https://github.com/bshoshany/thread-pool/blob/master/thread_pool.hpp#L389) line
0x102fa00bc (test_cxx_api_RoadRunnerMapTests:x86_64+0x1000130bc) type_traits:3635 
0x102f9ff1e std::__thread_execute<…> thread:286 
0x102f9f005 std::__thread_proxy<…> thread:297 
0x1033e9a2c __tsan_thread_start_func 
0x7fff204828fb _pthread_start 
0x7fff2047e442 thread_start 

析构函数的调用顺序与变量声明顺序相反。 v将在pool之前被销毁,因此当 pool 中的一些线程调用printString()时,参数字符串将不是有效的 object,因为v及其内容已经被销毁。 为了解决这个问题,我建议在pool之前声明v

如果你调试它,你会看到主线程在 thread_pool::~thread_pool() 的析构函数中。

#0  0x00007ffff7a7a3bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=0x7fffffffde48, rem=0x7fffffffde48) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
#1  0x00007ffff7a80047 in __GI___nanosleep (requested_time=<optimized out>, remaining=<optimized out>) at nanosleep.c:27
#2  0x000000000040e4ed in std::this_thread::sleep_for<long, std::ratio<1l, 1000000l> > (__rtime=...)
    at /ssd/depbuilder-1.1.3/bin/../lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/this_thread_sleep.h:82
#3  0x000000000040de09 in thread_pool::sleep_or_yield (this=0x7fffffffdfb0) at /home/hbucher/git/tests/threadpool/thread_pool.hpp:371
#4  0x000000000040faef in thread_pool::wait_for_tasks (this=0x7fffffffdfb0) at /home/hbucher/git/tests/threadpool/thread_pool.hpp:300
#5  0x000000000040c789 in thread_pool::~thread_pool (this=0x7fffffffdfb0) at /home/hbucher/git/tests/threadpool/thread_pool.hpp:62
#6  0x000000000040b9b9 in test_t_Test::TestBody (this=0x42bfb0) at /home/hbucher/git/tests/threadpool/threadpool.cpp:31
#7  0x00007ffff7fac03d in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
   from /ssd/depbuilder-1.1.3/lib/libgtest.so
#8  0x00007ffff7fa0b85 in testing::Test::Run() () from /ssd/depbuilder-1.1.3/lib/libgtest.so
#9  0x00007ffff7fa0cc8 in testing::TestInfo::Run() () from /ssd/depbuilder-1.1.3/lib/libgtest.so
#10 0x00007ffff7fa0da5 in testing::TestCase::Run() () from /ssd/depbuilder-1.1.3/lib/libgtest.so
#11 0x00007ffff7fa131c in testing::internal::UnitTestImpl::RunAllTests() () from /ssd/depbuilder-1.1.3/lib/libgtest.so
#12 0x00007ffff7fa1408 in testing::UnitTest::Run() () from /ssd/depbuilder-1.1.3/lib/libgtest.so
#13 0x00007ffff7fc30db in main () from /ssd/depbuilder-1.1.3/lib/libgtest_main.so
#14 0x00007ffff79c10b3 in __libc_start_main (main=0x7ffff7fc30a0 <main>, argc=1, argv=0x7fffffffe368, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe358)
    at ../csu/libc-start.c:308
#15 0x000000000040b61e in _start ()

这意味着线程池 object 正在被销毁,并且字符串向量已经被销毁,而线程仍在尝试使用它。

如果您交换变量的 position,您将确保测试成功运行到完成。

TEST(test, t)
{
    int N = 1000000;
    std::vector<std::string> v(N);
    thread_pool pool(16);
    for (int i = 0; i < N; i++)
    {
        v[i] = std::to_string(i);
    }
    for (auto &s : v)
    {
        pool.push_task([&s]()
                       { printString(s); });
    }
}
thread: 3 999996
thread: 15 999997
thread: 9 999998
thread: 13 999983
thread: 3 999964
[       OK ] test.t (27346 ms)
[----------] 1 test from test (27346 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (27347 ms total)
[  PASSED  ] 1 test.

传递给线程池的任务包含对向量v内容的引用,但是该向量在池留下悬空引用的任务之前离开 scope。 为了解决这个问题,您需要重新排序变量的范围:

int N = 1000000;
std::vector<std::string> v(N);
thread_pool pool(16);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM