列表和多线程环境

时间:2012-06-09 20:31:29

标签: c++ multithreading list stl

我是C ++标准库的新手,并且一直在使用标准库列表来实现特定的多线程实现。我注意到使用我在任何教程/博客/论坛帖子上都没有看过的列表可能会有一些技巧,虽然对我来说似乎显而易见,似乎没有人考虑过。所以也许我太新了,可能会遗漏一些东西,所以希望比我聪明的人可以验证我想要实现的目标,或者向我解释我做错了什么。

所以我们知道,通常标准库容器不是线程安全的 - 但这似乎不仅仅是一个规则的指导性声明。使用列表似乎对线程安全有一定程度的容忍度。让我解释一下,我们知道如果我们从列表中添加/删除列表不会失效。失效的唯一迭代器是已删除的项目 - 您可以使用以下代码行修复该项目:

it = myList.erase(it)

现在假设我们有两个线程并将它们称为线程1和线程2.

线程1的职责是添加到列表中。它将其视为队列,因此它使用std :: list :: push_back()函数调用。

线程2的职责是将存储在列表中的数据作为队列进行处理,然后在处理后将从列表中删除元素。

它保证线程2不会删除列表中刚刚在处理过程中添加的元素,并且线程1保证它将在线程2处理之前提前排队必要的数据。但是,请记住,在线程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知道当前最后一个元素的范围是灵活的,那么线程2也可以避免锁定。

有人看到我的建议有什么问题吗?

谢谢!

1 个答案:

答案 0 :(得分:5)

你的节目很活泼。作为一个明显的数据竞争的例子:std::list不仅仅是一个双重链接节点的集合。例如,它还有一个数据成员,用于存储列表中的节点数(它不需要是单个数据成员,但必须在某处存储计数)。

您的两个线程将同时修改此数据成员。因为这些修改没有同步,所以你的程序很活泼。

如果没有外部同步,标准库容器的实例不能同时从多个线程变异。