簡體   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