繁体   English   中英

C++ 中不同向量之间没有线程安全?

[英]No thread-safety between different vectors in C++?

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

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

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>>都可以。

一个问题是您的线程可以在构造函数返回之前调用toCall 在构造函数中创建回调对象的线程并不是一个好主意。 将线程创建推迟到某种startlaunch函数,并在构造函数返回后调用它。

这也是一个问题:

lols.push_back(ThreadClass());

在这里,(临时的)析构函数甚至可以在toCall之前运行! 那肯定行不通。 这是不在构造函数中创建线程的另一个很好的理由——它使临时对象变得灾难性。

暂无
暂无

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

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