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

时间:2012-12-17 10:59:25

标签: c++ windows-7 boost-thread point-cloud-library

我有一个简单的程序来测试我可以从不同的线程可视化点云并继续在主线程中工作,直到在终端中输入'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()函数上放了一些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 在新循环之前永远不会打印

另一方面,主线程继续计算并将这些点打印到标准输出,直到输入'q'

似乎viewer->spinOnce(100)调用中的可视化线程很多。如果我使用其他可视化方法spinOnce(100)代替spin(),则不会发生任何变化。

也许我的代码中存在数据竞争,但是我一直在检查它,我自己找不到竞赛。

注意:根据PCL库文档,spinOnce(int time) 调用交互器并更新屏幕,而spin() 调用交互器并运行内部循环

编辑#2:今天我尝试在Ubuntu中再次执行代码,导致PCL可视化器出现死锁。我添加了一些volatile个关键字和一个新的循环检查。现在它似乎进展顺利(至少它按预期工作,没有错误的转变...)。这是新版本:

Global vars:

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。是不是有更好的方法知道什么时候退出?现在,我无法实现任何其他方式...

1 个答案:

答案 0 :(得分:0)

我相信wasStopped()函数是一个const成员函数,因此不会改变对象的状态,所以这里可能会有一个优化(它可能会将wasStopped()值缓存为编译器假设答案不会改变。我建议你尝试将查看器包含在另一个具有函数bool wasStopped() volatile的对象中,这可能会阻止这种优化。