2

像 std::vector && 朋友这样的容器(我实际上正在使用 QList)是否会抛出一个可捕获的异常,或者如果一个线程在另一个线程正在读取容器时尝试写入容器,它是未定义的行为:

std::vector<std::string> stuff;

另一个线程中的非关键任务(例如拼写检查):

try {
    for (std::string& s : stuff) {
        //do stuff with s
    }
} catch (...) {  // Handle all exceptions
    //bail out of task
}

主线程:

stuff.erase(std::remove(someIterator), stuff.end()); 

所以你可以看到这里会有一个场景,它可能有一个无效的迭代器,并且将在读取线程中抛出一个异常 - 这将被捕获并退出任务。

但这只是一种情况——我是否可以依靠从这些容器中抛出可捕获的异常,这样我就不需要使用互斥锁来保护向量或字符串?或者在某些情况下它可能会取消引用 nullptr(或其他东西)并导致 SEH 异常 - 即我无法捕获并继续的事情。我认为答案是它可能依赖于实现,并且很可能会导致未定义的行为,但我想我会问这个问题。

4

3 回答 3

8

一般来说,您不能指望访问无效的迭代器会引发任何类型的异常。结果是未定义的行为:调用可能会抛出,它可能会崩溃,它可能会工作多年,然后再咬你,它可能会破坏程序中其他地方不相关的东西。

标准禁止对标准库的对象和函数做这种事情:

17.6.4.10/1:

如果从不同线程调用标准库函数可能会引入数据竞争,则程序的行为是未定义的。17.6.5.9 规定了可能发生这种情况的条件。

17.6.5.9/6:

通过调用标准库容器或字符串成员函数获得的迭代器上的操作可以访问底层容器,但不得修改它。[注意:特别是,使迭代器无效的容器操作与与该容器关联的迭代器上的操作相冲突。——尾注]

大多数 Qt 函数同样不是线程安全的。

如果您需要在线程之间共享数据,请保护自己免受数据竞争的影响。除非文档说明,否则不要指望图书馆为您做这件事。

于 2013-06-26T00:43:26.887 回答
1

使用无效的迭代器本身就是未定义的行为。它不会像您想象的那样抛出异常。因此,即使使用互斥,您的想法(除非我误解了)也不会成功。

访问相同 std:: 对象的数据竞争也是未定义行为的来源。

于 2013-06-26T00:42:10.123 回答
0

AFAIK 该标准没有说明 std::vector 等人的多线程行为。但实际上,每个人都将以最直接、最高效的方式实现事物,这意味着没有任何线程安全性。

MSDN记录了他们实现 STL 的行为。我希望主流实现之间没有差异。仅供参考,MSDN 文档的长短之处在于,如果您在其他线程中有读者并且正在修改容器,则行为将是未定义的。

于 2013-06-26T00:42:01.887 回答