2

現在、私のプロジェクトには 2 つの静的メソッドPushObjectsProcessObject. メソッドはデータを静的両端キューにプッシュバックし、このPushObjectメソッドは複数のスレッドからアクセスできますが、ProcessObject常に単一のスレッドで使用され、オブジェクトを上から取得して削除するために使用されます。常に最終的に(遅かれ早かれdeque iterator not dereferencableエラーが発生します。この問題を止めるために私ができることについての提案。私のPushObjectsとの要約をProcessObject以下に示します

    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

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
    }
}

この方法では、lock / get 1 item / unlock / process 1 item ではなく、lock / get all items / unlock / process all itemsになり、ミューテックスのロックはパフォーマンスに大きな影響を与えるため、はるかに効率的です。

明らかに、これはシングル コンシューマ モデル専用です。複数のコンシューマーがある場合、すべてのアイテムを 1 つのコンシューマーにエンキューして、他のすべてのコンシューマーをアイドル状態にしたくはありません。

于 2013-04-17T12:50:48.730 に答える
3

読み取り/書き込みミューテックスにアクセスするには、単一のミューテックスが必要です。mydequeまた、deque へのアクセスは、mutex がロックされている間でなければなりません。empty()をチェックするだけでも。deque 操作はアトミックではないためmydeque.empty()、push_back の途中でセミノンエンプティ状態にありながら、最終的に false を返す可能性があります。boost::lock_guard<boost::mutex> lock(mutex_push);したがって、mydeque への各アクセスの前に必要です 。または deque コンテンツを変更する全体の操作中に。

于 2013-04-17T12:18:42.893 に答える