我有一个简单的程序来测试我是否可以从不同的线程可视化点云并继续在主线程中工作,直到在终端中输入“q” 。
在 Ubuntu 10.04 中,代码有效,让我可以将云可视化为在每次迭代中添加新点。但是,在 Windows 7 中这不起作用(我正在使用QtCreator编译它)。显示云并在每一轮中计算新点,但这永远不会退出。输入'q'时,循环停止,但可视化线程继续运行。停止执行的唯一方法是显式使用CTRL+C。
更多的东西:
- 如果我不取消注释Visualize函数中的!viewer->wasStopped()循环之前的addPointCloud行,则永远不会显示点云。没关系,稍后在循环中我明确添加它。它必须在循环之前完成(现在该行已被注释以证明该行为)。
- 我还尝试使用boost::mutex而不是 *tbb::queuing_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()
在函数上添加了一些行(另外,现在我使用的是 volatile 中间 var,stoppedVisualize
,而不是直接调用):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 之前只显示一次,迭代=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。有没有更好的方法来知道何时退出?现在,我无法意识到任何其他方式......