如何在std :: deque中避免`deque iterator not dereferencable`?锁?

时间:2013-04-17 12:02:30

标签: c++ iterator mutex deque

目前在我的项目中,我有两个静态方法PushObjectsProcessObjectPushObject方法将数据推送回静态双端队列,多个线程可以访问此方法,但ProcessObject始终由单个线程使用,用于从顶部检索对象并删除它们。现在我的问题是无论我尝试什么,我总是最终(迟早会得到deque iterator not dereferencable错误。关于我可以做些什么来阻止这个问题的任何建议。我的PushObjects和{{1的摘要下面给出了

ProcessObject

从我所读到的是,一旦在deque中添加或删除项目,迭代器就会变为无效。有没有办法解决这个问题。

3 个答案:

答案 0 :(得分:5)

您似乎没有使用相同的互斥锁(mutex_push vs mutex_process)来读取/写入deque。你需要。写入内存并在不同线程上同时读取内存是不安全的。

其他说明:

obj a = mydeque.front();
......Process the object........
mydeque.pop_front();
如果您管理锁定以获得最短的锁定时间,那么

可能会好得多......

obj a = std::move(mydeque.front());
mydeque.pop_front();
lock.unlock();
// process the object
lock.lock();

您可能不需要锁定(或至少不需要相同的锁)来处理对象。通过这种方式,您的编写者仍然可以在处理时写入双端队列。另外需要注意的是,没有什么可以阻止你成为多生产者多消费者,而不仅仅是多生产者单一消费者。

答案 1 :(得分:4)

在您处理项目时,尽快扩展Dave关于解锁的答案以允许并发写入......

你的双端队列可能包含几个项目(例如,当你还在处理另一个项目时已被推送)。为了避免锁定每个项目,你可以将你的双端队列交换为空的本地项目,并处理来自该本地双端队列的项目。有些代码会更清晰:

while (true) {
    std::deque<Obj> tmp_deque;
    {
        std::unique_lock<std::mutex> lock(mutex);
        while (mydeque.empty())
            condition.wait(lock);
        mydeque.swap(tmp_deque);
    }
    while (!tmp_deque.empty()) {
        Obj obj = std::move(tmp_deque.front());
        tmp_deque.pop_front();
        // process obj
    }
}

通过这种方式,您可以使用锁定/获取所有项目/解锁/处理所有项目,而不是锁定/获取1项目/解锁/处理1项因为锁定互斥锁是一个很大的性能影响,因此效率更高。

显然,这仅适用于单一消费者模式。如果你有多个消费者,你真的不想让一个消费者中的所有商品入队,让所有其他消费者都闲着。

答案 2 :(得分:3)

您需要单个互斥锁才能访问mydeque无读/写互斥锁。任何对双端队列的访问都必须在互斥锁定时进行。即使你只是检查空()。由于deque操作不是原子操作,因此最终可能会返回mydeque.empty()返回false,而在push_back中间处于某种半空状态。因此,在每次访问mydeque之前,您需要boost::lock_guard<boost::mutex> lock(mutex_push);。或者在改变双端内容的整个操作过程中。