【发布时间】:2012-12-04 11:17:06
【问题描述】:
我有一个简单的程序来测试我是否可以从不同的线程可视化点云并继续在主线程中工作,直到在终端中输入 '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 无法识别可执行格式,我无法使用调试器(?)我在 Visualize 函数上放置了一些 qDebug() 行(另外,直接调用viewer->wasStopped() 现在我使用的是可变中间变量,stopped):
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;
};
嗯,Before spinOnce 只显示一次,iteration=0。 Before a new loop 行从不打印。
另一方面,主线程不断计算这些点并将其打印到标准输出,直到输入'q'。
似乎可视化线程在viewer->spinOnce(100) 调用中冻结。如果我使用另一种可视化方法 spin() 而不是 spinOnce(100),则没有任何变化。
也许我的代码中存在数据竞赛,但我一直在检查它,我自己找不到竞赛。
注意:根据 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。有没有更好的方法来知道何时退出?现在,我无法实现任何其他方式......
【问题讨论】:
-
在我看来,PCL 库在 Windows 上的另一个线程中呈现时存在问题。顺便说一句,
has_to_update也应该是 volatile 的。 -
是的,多线程渲染有问题。文档中有一条注释:
This class can NOT be used across multiple threads. Only call functions of objects of this class from the same thread that they were created in! Some methods, e.g. addPointCloud, will crash if called from other threads.。但是,在这篇文章中,作者使它起作用了:PCLVisualizer class。在 Ubuntu 中,它起作用了。我将尝试绕过 PCL 可视化库并直接使用 VTK。我会及时通知你进展:) -
@daramarak。我在问题中添加了一个新的“编辑”。似乎在 Ubuntu 中
spinOnce有时也会死锁,只是它不像在 Windows 中那样频繁。现在看来,我已经设法避免了这种情况。也就是说,Windows 中的新代码死锁,就好像没有进行任何更改一样。
标签: c++ windows-7 boost-thread point-cloud-library