0

私はそれを考え出した。私のばかげた間違いです。私は実際にキューから要素を削除していませんでした。最初の要素を読んでいただけです。コードを変更しましたが、以下のコードは機能しません。助けてくれてありがとう。

ブーストを使用して生産者と消費者の問題を実装しようとしていますが、これは実際にはより大きなプロジェクトの一部です。インターネット上の例からプログラムを実装し、ここで見つけたいくつかのヘルプも実装しました。ただし、現在、私のコードはハングアップしています。いくつかの良いアドバイスに基づいて、生産者と消費者の間でデータを保持するためにブースト循環バッファーを使用することにしました。似たようなコードがたくさんあり、それらからアイデアをプールして、自分で何かを書くことができました。ただし、以前と同じ問題が発生しているようです (これは私のプログラムがハングするだけです)。以前のようなミスはしなかったと思います..

私のコードを以下に示します。以前のコードを取り出して、私だけのリンク リストを作成しました。

バッファ ヘッダー:

#ifndef PCDBUFFER_H
#define PCDBUFFER_H

#include <pcl/io/pcd_io.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/circular_buffer.hpp>

class pcdBuffer
{
    public:
        pcdBuffer(int buffSize);
        void put(int data);
        int get();
        bool isFull();
        bool isEmpty();
        int getSize();
        int getCapacity();
    private:
        boost::mutex bmutex;
        boost::condition_variable buffEmpty;
        boost::condition_variable buffFull;
        boost::circular_buffer<int> buffer;
};


#endif

バッファ ソース (関連する部分のみ):

#include "pcdBuffer.h"
#include <iostream>

//boost::mutex io_mutex;

pcdBuffer::pcdBuffer(int buffSize)
{
    buffer.set_capacity(buffSize);
}

void pcdBuffer::put(int data)
{
    {
        boost::mutex::scoped_lock buffLock(bmutex);
        while(buffer.full())
        {
            std::cout << "Buffer is full" << std::endl;
            buffFull.wait(buffLock);
        }
        buffer.push_back(data);
    }
    buffEmpty.notify_one();
}

int pcdBuffer::get()
{
    int data;
    {
        boost::mutex::scoped_lock buffLock(bmutex);
        while(buffer.empty())
        {
            std::cout << "Buffer is empty" << std::endl;
            buffEmpty.wait(buffLock);
        }
        data = buffer.front();
            buffer.pop_front();
    }
    buffFull.notify_one();
    return data;
}

コードの主なドライバー:

#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <unistd.h>
#include "pcdBuffer.h"

pcdBuffer buff(100);

void producer()
{
    int i = 10;
    while (true)
    {
        buff.put(i);
        i++;
    }
}

void consumer()
{
    int i;
    while(true)
    {
        i = buff.get();
        std::cout << "Data: " << i << std::endl;
    }
}

int main(int argc, char** argv)
{
    std::cout << "Starting main...." << std::endl;
    std::cout << "Buffer Details: " << std::endl;
    std::cout << "Capacity: " << buff.getCapacity() << ", isEmpty: " << buff.isEmpty() << ", isFull: " << buff.isFull() << std::endl;
    boost::thread cons(consumer);
    sleep(5);
    boost::thread prod(producer);
    prod.join();
    cons.join();
    return 0;
}

バッファ容量は正しく 100 に初期化されています。コンシューマ スレッドは待機し、「バッファが空です」と 5 秒間報告しますが、その後、put メソッドから「バッファがいっぱいです」と「データ : 10」を取得します。 stdout を交互に使用するコンシューマー関数。ご覧のとおり、10 は最初に入力した要素です。バッファーがいっぱいになり、消費者に通知していないようですが、ロックを確認したところ、正しいと思います。これに関するヘルプは大歓迎です。

このコードを書いた参考文献のリンクは次のとおりです。

http://www.boost.org/doc/libs/1_49_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_19ba12c0142a21a7d960877c22fa3ea00

http://www.drdobbs.com/article/print?articleId=184401518&siteSectionName=cpp

循環バッファのスレッドセーフな実装

4

3 に答える 3

5

まず第一に、独自のリストを作成する代わりに、独自のリストを作成する代わりにラップすることができstd::listますpcdQueue。それは正しいです、それはそのままではstd::listスレッドセーフではありませんが、とにかくクラスに必要な同期プリミティブを提供しています。

プログラムがハングする理由: ロックを保持し、いっぱいになるまでキューをいっぱいにします。notify_oneミューテックスはすでに(プロデューサーのロックによって)取得されているため、コンシューマーは再びロックされるため、コンシューマーへの通知は役に立ちません。

を待機して最終的にロックを解除すると (キューがいっぱいになったとき) condition_variable、コンシューマーを起動しないため、コンシューマーとプロデューサーの両方がブロックされ、プログラムがハングします。

次のように変更します。

void pcdQueue::produce()
{
    int i=0;
    while(true)
    {
        {
            boost::mutex::scoped_lock lock(qmutex);
            while( ! qlen < buffSize ) {
                std::cout << "Queue is full" << std::endl;
                full.wait(lock);
            }

            enqueue(i); // or myList.push_back(i) if you switch to std::list
        }

        empty.notify_one();


    }
}

メソッドにも同じ問題がありますconsume()。次のように変更します。

pcdFrame* pcdQueue::consume()
{
    pcdFrame *frame;

    {
        boost::mutex::scoped_lock lock(qmutex);
        while( qlen == 0 ) {
            std::cout << "Queue is empty" << std::endl;
            empty.wait(lock);
        }

        frame = dequeue();
    }
    full.notify_one();

    return frame;
}

一般に、通知は誰かが待っている場合にのみ効果があることに注意してください。それ以外の場合、それらは「失われます」。さらに、呼び出し時にミューテックスをロックしておく必要がないことに注意してくださいnotify_one(実際には、現在 (まだ) ミューテックスを待機する他のスレッドをウェイクアップするため、コンテキストスイッチのオーバーヘッドが追加される可能性があります。 (あなたによって) ロックされているので、最初にミューテックスを解放してから、他のスレッドに続行するよう伝えます。

両方のスレッドが無限に実行されるため、メイン プログラムは最初にハングし、終了しないことに注意してくださいjoin()whileスレッドに終了を指示するために -loops にチェックする停止フラグを含めることができます。

于 2012-04-17T12:05:37.883 に答える
0

Boost は現在、ロックフリー セクションでプロデューサー/コンシューマー キュー タイプを提供しています。

ドキュメントは次の場所にあります。

http://www.boost.org/doc/libs/1_54_0/doc/html/lockfree.html

これはかなり最近追加されたものなので、まだ多くの標準パッケージには含まれていないと思います。一方、これはほとんどヘッダーのように見えますが、すべては長い間後押しされてきたかなり低レベルのシステムに依存しています。

于 2013-08-09T03:39:34.530 に答える