我是C++标准库的新手,并且一直在使用标准库列表来实现特定的多线程。我注意到,使用列表可能有一个技巧,我在任何教程/博客/论坛帖子上都没有看到过,尽管对我来说似乎很明显,但似乎没有人考虑过。因此,也许我太新了,可能会错过一些东西,所以希望有比我更聪明的人可以验证我正在努力实现的目标,或者向我解释我做错了什么。
所以我们知道,一般来说,标准库容器不是线程安全的--但这看起来更像是一条指导性的声明,而不是一条规则。对于列表,似乎有一定程度的线程安全容忍度。让我解释一下,我们知道如果我们从列表中添加/删除列表,列表不会失效。唯一无效的迭代器是已删除的项-您可以使用以下代码行来修复它:
it = myList.erase(it)现在假设我们有两个线程,分别称为线程1和线程2。
线程1的职责是添加到列表中。它将其视为一个队列,因此它使用std::list::push_back()函数调用。
线程2的职责是将存储在列表中的数据作为一个队列进行处理,然后在处理之后将从列表中删除元素。
它保证Thread2不会删除在处理过程中刚刚添加的列表中的元素,而Thread1保证它会将必要的数据排在Thread2处理的前面。但是,请记住,可以在线程2的处理过程中添加元素。
因此,在这个多线程环境中,这似乎是一个合理的使用列表,而不使用锁来保护数据。我之所以说它是合理的,是因为从本质上讲,线程2到目前为止只会处理数据,这样它就可以检索到如下伪代码所示的当前结束迭代器:
Thread 2 {
iter = myList.begin();
lock();
iterEnd = myList.end(); // lock data temporarily in order to get the current
// last element in the list
unlock();
// perform necessary processing
while (iter != iterEnd) {
// process data
// ...
// remove element
iter = myList.erase(iter);
}
}线程2使用锁的时间非常短,只是为了知道在哪里停止处理,但在大多数情况下,线程1和线程2不需要任何其他锁。此外,如果线程2知道当前最后一个元素的作用域是灵活的,那么它也可以避免锁定。
有没有人觉得我的建议有问题?
谢谢!
发布于 2012-06-10 04:53:08
你的程序很有活力。举一个明显的数据竞赛的例子:std::list不仅仅是一个双向链接节点的集合。例如,它还有一个存储列表中节点数量的数据成员(它不需要是单个数据成员,但必须将计数存储在某个地方)。
您的两个线程将同时修改此数据成员。因为这些修改没有同步,所以你的程序是活泼的。
在没有外部同步的情况下,无法从多个线程并发地变异标准库容器的实例。
https://stackoverflow.com/questions/10964383
复制相似问题