Boost.thread代码在Ubuntu和Windows中表现出不同的行为



我有一个简单的程序来测试我是否可以从不同的线程可视化点云,并继续在主线程中工作,直到在终端中键入'q'

在Ubuntu10.04中,代码可以工作,让我在每次迭代中都可以看到云的新点。然而,在Windows7中,这是不起作用的(我正在用QtCreator编译它)。会显示云,并在每一轮中计算新的点,但这永远不会退出。当键入'q'时,循环会停止,但可视化线程会继续运行。停止执行的唯一方法是显式使用CTRL+C

更多内容:

  • 如果我不取消注释之前的addPointCloud行!viewer->wasStopped()循环,在Visualize函数中,点云永远不会显示。在循环的后面,我显式地添加它并不重要。它必须在循环之前完成(现在对该行进行了注释,以演示这种行为)
  • 我还尝试使用boost::mutex而不是*tbb::queuing_tmute*,但程序不会退出

你知道为什么线程永远不会加入吗?。此外,对我的线程使用提出建设性的批评总是很受欢迎的,我想不断改进。

这是代码:

#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(),而是一个易失性中间变量,已停止):

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只显示一次,迭代=0。新循环之前的从不打印。

另一方面,主线程继续计算这些点并将其打印到标准输出,直到输入'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破解。难道没有更好的方法知道什么时候退出吗?。现在,我无法意识到任何其他方式。。。

我认为wasStopped()函数是一个常量成员函数,因此不会更改对象的状态,因此这里可能正在进行优化(它可能会缓存wasStopped()值,因为编译器认为答案不会更改。我建议您尝试用函数bool wasStopped() volatile将查看器包装在另一个对象中,这可能会阻止此类优化。

相关内容

最新更新