2

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

    void foo::PushObjects(obj A)
    {
        try
        {
            {//Begin Lock
                boost::lock_guard<boost::mutex> lock(mutex_push);
                mydeque.push_back(A);
            }//End Lock
            condition_read.notify_one(); //Inform the reader that it could start reading 
        }
        catch (std::exception& e)
        {
            __debugbreak();
        }
    }


    This is the static Reader method

    void foo::ProcessObject()
    {
        {//Begin Lock
            boost::unique_lock<boost::mutex> lock(mutex_process);
            while(true)
            {
                    while(mydeque.empty()) { condition_read.wait(lock); }
                    try
                    {
                        if(!mydeque.empty())
                        {
                                obj a = mydeque.front();
                                ......Process the object........
                                mydeque.pop_front();
                        }

                    }
                    catch (std::exception& e)
                    {
                        __debugbreak();
                    }
            }//end while
        }//End lock
    }

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

4

3 回答 3

5

看起来您没有使用相同的互斥锁(mutex_pushvs 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();

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

于 2013-04-17T12:16:17.940 回答
4

为了扩大戴夫关于尽快解锁的答案,以便在您处理项目时允许并发写入......

您的双端队列可能包含多个项目(例如,当您仍在处理另一个项目时,这些项目已被推送)。为了避免锁定每个项目,您可以将您的双端队列与一个空的本地队列交换,并从该本地双端队列处理您的项目。一些代码会使它更清晰:

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 个项目,而是锁定/获取所有项目/解锁/处理所有项目,因为锁定互斥锁对性能有很大影响,所以效率更高。

显然,这仅适用于单一消费者模型。如果您有多个消费者,您真的不希望将所有项目排入单个消费者并让所有其他消费者闲置。

于 2013-04-17T12:50:48.730 回答
3

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

于 2013-04-17T12:18:42.893 回答