別のスレッドから点群を視覚化し、ターミナルで「q」と入力するまでメインスレッドで作業を続けることができるかどうかをテストするための少し簡単なプログラムがあります。
Ubuntu 10.04 では、コードが機能し、反復ごとに新しいポイントが雲に追加される様子を視覚化できます。ただし、Windows 7 ではこれは機能しません (私はQtCreatorでコンパイルしています)。クラウドが表示され、ターンごとに新しいポイントが計算されますが、これは終了しません。'q'と入力すると、ループは停止しますが、視覚化スレッドは実行され続けます。実行を停止する唯一の方法は、明示的にCTRL+Cを使用することです。
より多くの事:
- Visualize関数の!viewer->wasStopped()ループの前にaddPointCloud行のコメントを外さないと、点群が表示されません。ループの後半で明示的に追加しても問題ありません。ループの前に実行する必要があります (その動作を示すために、その行にコメントが付けられています)。
- また、*tbb::queuing_mutex* の代わりにboost::mutexを使用しようとしましたが、プログラムは終了しません。
スレッドが参加しない理由がわかりましたか? また、私のスレッドの使用法に関する建設的な批評はいつでも歓迎されます。私は改善し続けたいと思っています。
コードは次のとおりです。
#include <boost/thread/thread.hpp>
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include "tbb/queuing_mutex.h"
typedef pcl::PointXYZ PointType;
typedef pcl::PointCloud<PointType> PointCloudType;
typedef tbb::queuing_mutex MutexType;
//typedef boost::mutex MutexType;
MutexType safe_update;
const unsigned int HEIGHT = 100;
const unsigned int WIDTH = 100;
bool has_to_update(true);
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
// viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped()) {
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
int main(int argc, char** argv) {
PointCloudType::Ptr c(new PointCloudType);
c->height=HEIGHT;
c->width=WIDTH;
const unsigned int size( c->height*c->width);
c->points.resize(size);
for(unsigned int i(0);i<size;++i){
c->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cout << "Filled cloud height: " << c->height << " ** widht = "
<< c->width << " ** size: " << c->points.size()
<< "\n"
;
boost::thread vis_thread( boost::bind( &Visualize, boost::ref(c) ) );
char exit;
std::vector<PointType> new_points;
new_points.resize(10);
PointType new_point;
while(exit!='q') {
for(unsigned int i(0);i<10;++i) {
new_point.x = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.y = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.z = 2000 * rand () / (RAND_MAX + 1.0f);
std::cout << "New point " << i << " with x = " << new_point.x
<< " ; y = " << new_point.y << " ; z = "
<< new_point.z << "\n"
;
new_points.push_back(new_point);
}
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
c->insert( c->points.end(), new_points.begin(), new_points.end() );
has_to_update = true;
} // end scoped_lock
std::cout << "Exit?: ";
std::cin>>exit;
}
vis_thread.join();
return 0;
}
御時間ありがとうございます!。
編集: Windows が実行可能形式を認識しないためにデバッガーを使用できないため (?) qDebug()
、関数にいくつかの行を追加しましたVisualize
(また、直接呼び出す代わりにviewer->wasStopped()
、揮発性の中間変数を使用して停止しました):
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
volatile bool stopped( false );
int iterations( -1 );
while(!stopped) {
++iterations;
qDebug() << "Before spinOnce - it: << iteration << "\n";
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
stopped = viewer->wasStopped();
qDebug() << "Before a new loop - it:" << iteration << "\n";
}
delete viewer;
};
さて、前の spinOnceはiteration=0で一度だけ表示されます。Before a new loop行は印刷されません。
一方、メインスレッドは、 「q」が入力されるまで、それらのポイントを計算して標準出力に出力し続けます。
可視化スレッドがviewer->spinOnce(100)
呼び出しでフリーズしたようです。代わりにspinOnce(100)
他の視覚化方法を使用してもspin()
、何も変わりません。
私のコードにデータ競合があるのかもしれませんが、私はそれをチェックし続けていますが、自分で競合を見つけることができません。
注: PCL ライブラリのドキュメントによるとspinOnce(int time)
、インタラクターを呼び出して画面を一度更新するのに対しspin()
、インタラクターを呼び出して内部ループを実行します。
編集 #2:今日、Ubuntu でコードを再度実行しようとしたところ、PCL ビジュアライザーでデッドロックが発生しました。volatile
いくつかのキーワードと新しいループ チェックを追加しました。今はうまくいっているようです (少なくとも期待どおりに機能し、間違った方向に曲がることはありませんでした...)。新しいバージョンは次のとおりです。
グローバル変数:
volatile bool has_to_update(true); // as suggested by @daramarak
volatile bool quit(false); // new while loop control var
視覚化方法:
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped() && !quit ) {
viewer->spinOnce(100);
{
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
主な機能:
// everything the same until...
std::cin>>exit;
quit = (exit=='q');
// no more changes
ただし、新しい制御ループ var hack は好きではありません。いつ終了するかを知るためのより良い方法はありませんか?. 今のところ、それ以外の方法はわかりません...