这个简单的多线程代码是如何导致内存损坏的?

问题描述 投票:0回答:2

以下代码可靠地产生段错误。

#include <vector>
#include <thread>

class Class {
public:
    Class(const int integer)
        : cinteger(integer), carray(std::array<int, 1>{0})
    {}

   const int operator()() 
   {
    carray[cinteger] = 0;
        return cinteger;
    }
    
private:
    int cinteger;
    std::array<int, 1> carray;
};

class Worker{
    public:
        Worker( Class iClass): 
            wClass(iClass),
            thread(&Worker::thread_main, this)
            {}
        
        void join(){thread.join();}     

    private:
        Class wClass;
        std::thread thread;
        void thread_main(){
            for(int i = 0; i < 50000; i++)
            wClass();
        }
};

int main()
{
    std::vector<Worker> Workers;
    for(int i = 0; i < 4; i++)
        Workers.emplace_back(Class(0));
    for(int i = 0; i < 4; i++)
        Workers[i].join();
    return 0;
}

出于某种原因,我不明白,Class 的

cinteger
变量似乎被意外更改了。每次运行代码都会出现这个问题。如果我只生成 3 个工人,它就不会出现。此外,在 Worker 类中进行 1000 次迭代时,问题不会出现。

TBH 我有点不知道这个问题可能来自哪里。

c++ multithreading c++11 stdthread
2个回答
7
投票

这真的很简单。在您引用

this
的线程中,但是当您在向量中执行
emplace_back
时,它最终会导致调整向量的大小并将对象移动到内存中的不同位置。使以前的实例无效。这导致
this
thread_main()
成员函数内部无效和损坏。


4
投票

除了其他答案提供的原因外,解决此问题的一种简单方法是简单地动态分配

Worker
类。将
vector<Worker>
替换为
std::vector<std::unique_ptr<Worker>>
,并相应地修复插入内容。

这将使您的工作人员对

vector
调整大小引起的重新分配不敏感,这比调用
.reserve
更稳健,因为您不需要提前知道工作人员的数量。
这是因为 pointed
Worker
将停留在它所在的位置,它将被动态分配并且不存在于向量中。

如果您 do 知道,那么您可以使用

.reserve
解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.