Код Boost.thread демонстрирует различное поведение в Ubuntu и Windows.

У меня есть небольшая простая программа для тестирования, могу ли я визуализировать облако точек из другого потока и продолжать работать в основном потоке до тех пор, пока не наберу текст «Д» в терминале.

В Ubuntu 10.04 код работает, что позволяет мне визуализировать облако по мере добавления новых точек к нему на каждой итерации. Тем не менее, в Windows 7 это не работает (я собираю его с QtCreator). Облако показано, и новые точки вычисляются в каждом повороте, но это никогда не выходит. При наборе текста «Д», цикл останавливается, но поток визуализации продолжает работать. Единственный способ остановить выполнение — явно использовать CTRL + C.

Больше вещей:

  • Если я не раскомментирую addPointCloud линия перед !viewer-> wasStopped () петля в Визуализируйте функция, облако точек никогда не отображается. Неважно, что позже в цикле я добавлю это явно. Это должно быть сделано до цикла (теперь эта строка комментируется, чтобы продемонстрировать это поведение).
  • Я также пытался использовать повышение :: мьютекс вместо * 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 отображается только один раз, с Итерация = 0. Перед новым циклом линия никогда не печатается.

С другой стороны, основной поток продолжает вычислять и печатать эти точки на стандартный вывод до тех пор «Д» вводится.

Кажется, что нить визуализации застывает в 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. Разве нет лучшего способа узнать, когда выходить? Прямо сейчас я не могу понять другой путь …

1

Решение

Я считаю, что wasStopped() функция является константной функцией-членом, таким образом, не изменяя состояние объекта, поэтому здесь может происходить оптимизация (она может кэшировать wasStopped() значение, поскольку компилятор предполагает, что ответ не изменится. Я предлагаю вам попытаться обернуть зрителя в другой объект с помощью функции bool wasStopped() volatile, что может помешать такой оптимизации.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]