【问题标题】:C++ Vector, push_back from another thread crashing?C ++ Vector,来自另一个线程的push_back崩溃?
【发布时间】:2010-12-10 14:57:50
【问题描述】:

在我的代码中使用已检查的 STL 实现时出现意外断言失败。

经过一番研究,我将问题缩小到一个向量中的 push_back,该向量是从与创建向量的线程不同的线程调用的。

重现此问题的最简单代码是:

class SomeClass
    {
    private:
        std::vector<int> theVector;
    public:
        SomeClass () 
        {
            theVector.push_back(1); // Ok
        }


        void add()
     {
          theVector.push_back(1); // Crash 
     }
};

唯一的区别是 SomeClass 是从我的主线程实例化的,而 add 是从另一个线程调用的。但是,不存在并发问题:在我用于故障排除的最简单形式的代码中,除了我上面提到的情况之外,没有人从这个向量中读取或写入。

跟踪 push_back 代码,我注意到 std::vector 中的某些方法(如 count() 或 size())在从另一个线程(方法“add”)调用时返回垃圾,并在从创建线程(例如在构造函数中)

我是否应该断定 std::vector 在多线程环境中不可用?或者有没有解决这个问题的方法?

编辑:删除易失性

编辑 2:您认为问题可能不在于多线程吗?在我的测试运行中, add 仅被调用一次(使用断点验证)。如果我从构造函数中删除 push_back,我仍然会崩溃。所以最后,即使只调用一次向量的方法,在调用一次的函数中也会使断言失败。因此不能有并发,或者......?

【问题讨论】:

  • 如果确实没有并发向量应该工作。如果有 2 个或更多线程并行使用向量,这将不起作用。
  • 您是否处于每个线程都有自己的堆的环境中?
  • -1:您的代码甚至无法编译,因为push_back() 未声明为“易失性”。能否提供更详细的代码/说明?
  • “我应该断定 std::vector 在多线程环境中不可用吗?” -- 一点也不,vector 在多线程应用程序中的作用与在单线程应用程序中的作用不一样。事实上,如果你比较 C++0x(它是线程感知的)向量与 C++97(它不是线程感知的)没有任何不同。在必要时提供序列化是应用程序而不是向量的责任。在您的情况下,我认为您关于多线程在可观察行为中没有作用的断言可能是错误的,请进行适当的锁定而不是推测。
  • @JimR - 那会是什么?线程始终共享同一个免费存储,这是线程安全的,这是标准要求。

标签: c++ multithreading stl vector thread-safety


【解决方案1】:

std::vector 绝对可以在多线程环境中使用,前提是您不要同时从两个线程访问向量。我一直都在做,没有麻烦。

由于vector 不是问题,您需要更仔细地查看您的同步机制,因为这很可能是问题所在。

我注意到您将vector 标记为volatile。您是否期望将其设为volatile 将提供同步?因为不会。 See here for more information.

编辑:最初提供的链接错误。现在已修复。很抱歉造成混乱。

【讨论】:

  • 抱歉,volatile 是错误的,而且如前所述,它甚至无法编译。 D
【解决方案2】:

如果您可以保证在调用 push_back 时没有人在对向量进行写入或读取,那么它没有理由失败。您可能正在处理更高级别的内存损坏。您应该验证“this”是否指向 SomeClass 的真实实例,检查它的其他成员等。

【讨论】:

  • 你们确实是对的:问题不在于 vactor 或线程,而是 SomeClass 实例。非常感谢您的想法
【解决方案3】:

大多数 STL 实现都不是线程安全的。您需要使用线程同步(例如互斥锁)来防止两个线程在访问向量时相互踩踏。基本上,您需要做的是创建一个类,其中包含向量、互斥体和访问器函数,用于保护向量的读写操作。

【讨论】:

  • @Gene:我认为当人们说“线程安全”时,他们的意思是“能够在线程中使用而无需做任何特别的事情。”
  • 此答案包含与@pts 相同的错误。互斥锁和同步在这里完全无关紧要。
  • @John:吉恩的定义和任何人的一样好。 “线程安全”是一个毫无价值的限定词,因为没有两个人就其含义达成一致。
  • @Konrad:我同意“线程安全”是一个无用的短语。只是带来另一种可能普遍的看法。
  • @John Dibling -- “人”可以“意味着”很多东西,我们不是在这里讨论心理学。你不能以任何你想要的方式使用稳定的概念,尤其是当这种使用没有意义时。
【解决方案4】:

标准库是否支持多线程是实现定义的。您必须阅读特定编译器的文档。

此外,您还可以添加一些日志消息,如下代码所示:

class SomeClass
    {
    private:
        volatile std::vector<int> theVector;
    public:
        SomeClass () 
        {
            std::cout << "SomeClass::SomeClass" << std::endl;
            theVector.push_back(1); // Ok
        }
        ~SomeClass ()
        {
            std::cout << "SomeClass::~SomeClass" << std::endl;
        }
        void add()
        {
            std::cout << "SomeClass::add" << std::endl;
            theVector.push_back(1);
        }
};

确保调用add 函数时SomeClass 的实例仍然存在。

【讨论】:

    猜你喜欢
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多