BoostライブラリのCircular_bufferはスレッドセーフではありません。そのため、以下に示すように、boost :: circular_bufferオブジェクトをクラスでラップしました。スレッド間の相互排除は、条件変数、ミューテックス、ロックの取得/解放を使用することで実現されます(私はそう思います)。この実装スレッドは安全ですか?
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/circular_buffer.hpp>
// Thread safe circular buffer
template <typename T>
class circ_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
circ_buffer() {}
circ_buffer(int n) {cb.set_capacity(n);}
void send (T imdata) {
lock lk(monitor);
cb.Push_back(imdata);
buffer_not_empty.notify_one();
}
T receive() {
lock lk(monitor);
while (cb.empty())
buffer_not_empty.wait(lk);
T imdata = cb.front();
cb.pop_front();
return imdata;
}
void clear() {
lock lk(monitor);
cb.clear();
}
int size() {
lock lk(monitor);
return cb.size();
}
void set_capacity(int capacity) {
lock lk(monitor);
cb.set_capacity(capacity);
}
private:
boost::condition buffer_not_empty;
boost::mutex monitor;
boost::circular_buffer<T> cb;
};
編集これは、(cv::Mat
オブジェクトだけでなく)任意のタイプのオブジェクトを受け入れるテンプレートクラスになりました。
はい。
すべてのパブリックメソッドを同じロックでロックすると、スレッドセーフになります。
読み取り/書き込みロックの使用を検討できます。これは、同時読み取りが多い場合にパフォーマンスが向上する可能性があります。
読者が少ない場合はオーバーヘッドが増えるだけですが、オプションを確認してテストする価値があります。
send
で作成されたMatの無意味なコピーがいくつかあることを除いて、私はそれがうまく見えると思います。新しいものは必要ありません。send
の引数を直接cbにプッシュできます。
あなたの実装は、この blogger で示されているものと似ています。そのブログを読んで、実装で何かを見落としていないか確認してください。
Mat
オブジェクトの作成/コピーにコストがかかる場合は、継続的に作成/コピー/削除することは避けてください。代わりに、ある種のパイプラインアーキテクチャでrecycledを継続的に取得するMatオブジェクトのプール(別名フリーリスト)が必要です。このタイプのアーキテクチャについては、関連する質問のこの answer で説明します。
その答えでは、ブロッキングスタックを使用してプールを実装することをお勧めしましたが、ブロッキングcircular_buffer
。スタックを提案した理由は、キャッシュフレンドリーである可能性があると思ったからですが、実際にそれが違いを生むかどうかを測定することはありませんでした。
buffer_not_full
条件をまったく使用していないことを除いて、一見すると見栄えがします。おそらく、buffer_not_empty
コードに類似したコードを追加する必要があります。