c++ - C++ 中不同 vector 之间没有线程安全?

标签 c++ multithreading vector thread-safety std

我的问题涉及同时使用不同的 vector 。我知道我不能指望同一个 vector 同时在多个线程中工作。我已经分解了该程序,以便更容易理解。我有一个 ThreadClass 类,它有一个构造函数,它只向 vector k 添加一个元素,然后调用一个线程 toCall ,然后输出大小应该是 1 的 vector 。此类的对象是使用 vector 的 push_back 成员在 main() 函数内的不同 vector 内创建的。

输出结果是0。有时我也能得到1。如果我切换到 Debug模式,我可以产生更多的数字 1。我已经在 gnu C++17 编译器 (Ubuntu 16.04) 和 Visual Studio 编译器 (Windows 10) 上测试了这个问题。现在我的问题是,这个示例是否表明我应该完全避免在多线程程序中使用 vector ?

class ThreadClass 
{
private:
    std::vector<int> k;
    std::thread thr;
public:
    ThreadClass() {
        k.push_back(27);
        thr = std::thread(&ThreadClass::toCall, this);
    }
    void toCall() {
        std::cout << k.size() << std::endl;
    }
    void close() {
        if (thr.joinable())thr.join();
    }
};

int main(){
    std::vector<ThreadClass> lols;
    lols.push_back(ThreadClass());
    lols[0].close();
    return 0;
}

最佳答案

问题是 ThreadClass 类型的值持有对其自身的引用。具体来说,thr包含 this 的拷贝。

当您复制或移动此类值时,例如当临时ThreadClass()移入lols ,重复项包含重复项 this ptr,即它指向旧的临时变量,其生命周期在调用lols.push_back后结束完成。

我们可以在没有线程的情况下复制这个问题:

class Foo
{
private:
    std::vector<int> k;
    Foo* possibly_this;
public:
    Foo() {
        k.push_back(27);
        possibly_this = this;
    }
    void toCall() {
        std::cout << possibly_this->k.size() << std::endl;
    }
};

int main(){
    std::vector<Foo> lols;
    lols.push_back(Foo{});
    lols[0].toCall();
}

(对我来说,它在 7.3.1 上使用 -O0 打印 0,但同样,它是 UB,因此它可以在您的计算机上执行任何操作。)

lols.emplace()不会有帮助。如果 std::vector调整大小,然后指向其中的所有指针/迭代器都将失效。不幸的是,您无法更改存储在 thr 中的指针。 ,所以你只剩下一个解决方案:禁用 ThreadClass的复制和移动构造函数,如下所示:

  //within the definition of ThreadClass
  ThreadClass(ThreadClass const&) = delete;

为了放置ThreadClass在容器中,您将需要额外的间接级别以允许 ThreadClass 类型值的实际对象要有一个稳定的位置。要么 std::list<ThreadClass>std::vector<std::unique_ptr<ThreadClass>>就可以了。

关于c++ - C++ 中不同 vector 之间没有线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57014061/

相关文章:

c++ - SDL_事件e;传递给函数

c++ - 基于类型创建具有默认参数的模板

c++ - 从 CUDA 设备函数/内核中并行化一个方法

c++ - 在C++容器中作为模板参数提供的分配器与作为构造函数参数提供的分配器之间的区别?

c++ - 跟踪 vector 中的智能指针

c++ - 错误 : invalid conversion from 'unsigned char*' to 'const signed char*'

java - 避免主线程上 I/O 操作的最佳方法是什么

iphone - GCD : How to write and read to variable from two threads

c++ - 在 C++ 中将 float 的文本文件读入二维 vector

c++ - 删除前手动调用析构函数