Boost:: поток, перенасыщение и обмен данными

Я думаю, что у меня есть проблема в моей программе. Я должен создать объект, который непрерывно взаимодействует с внешней системой слежения и получает от нее координаты точки. Я обернул этот класс внутри boost::thread и перед первыми вызовами моего приложения Glut я создаю объект потока и отсоединяю его

Код для существенных методов класса следующий

boost::mutex resourceMutex;

void Tracker::init()
{  
  boost::mutex::scoped_lock lock(resourceMutex);

  try
  {
    // some initializations
  }
  catch (std::bad_alloc const&)
  {  
     cerr << "Memory allocation fail during init!" << endl;
  }

  try
  {  
     p3dData = (Position3d*)calloc( NUM_MARKERS , sizeof( Position3d ) );
     if ( p3dData==NULL )
       throw std::bad_alloc();
  }
  catch ( std::bad_alloc const&)
  {  
     cerr << "Memory allocation fail during memory allocation!" << endl;
  }

}

void Tracker::update()
{
  boost::mutex::scoped_lock lock(optotrakResourceMutex);
  //... operations on vector< Eigen::Vector3d > points
}

vector<Eigen::Vector3d> &Tracker::getAllPoints()
{
  return points;
}

Мой glutTimerFunc вызывает функцию обновления, в которой каждый кадр выбирает точки с помощью метода getAllPoints, в то время как поток трекера непрерывно обновляет их (на самом деле частоты доступа к данным различны, поток вызывает к ним быстрее, чем функции обновления перенасыщения). звонки.

Теперь, когда программа завершает работу, я сначала удаляю объект Tracker, выделенный с помощью new, а затем прерываю поток, содержащий его, но иногда я получаю странное поведение, я думаю, что это утечка памяти

Является ли способ получения данных с разными частотами доступа и использование scoped_lock правильным или я должен поставить некоторую защиту в методе getAllPoints?

1 ответ

Решение

Я так понимаю твой выделенный трекер постоянно звонит Tracker::update() получить данные о локализации с вашего устройства (NDI Optotrak?)

Затем ваше приложение OpenGL получает доступ к последним точкам через регулярный интервал из основного потока, используя Tracker::getAllPoints(),

В этом случае вектор трехмерных точек Tracker::points является общим ресурсом между этими двумя потоками.

Чтобы предотвратить одновременный доступ, обе операции записи в update() и чтение с getAllPoints() должен быть защищен мьютексом, а не только написанием, как в вашем текущем коде. Код чтения в основном потоке также должен блокировать мьютекс:

// In your main application:
void timerFunc()
{
    Tracker* tracker = ...;            // Obtain a pointer to the tracker object
    tracker->LockResourceMutex();      // Enter critical section
    vector< Eigen::Vector3d >& pointsRef = tracker->getAllPoints();
    //... operations on points, protected by the mutex
    tracker->UnlockResourceMutex();    // Leave critical section
}

// In class Tracker:
void Tracker::LockResourceMutex() { optotrakResourceMutex.lock(); }
void Tracker::UnlockResourceMutex() { optotrakResourceMutex.unlock(); }

Предостережение: если ваши операции над точками в timerFunc() медленные, тогда мьютекс останется заблокированным на долгое время, и ваш поток трекера заблокирует его при вызове Tracker::update(),

Лучше дизайн будет меняться Tracker::getAllPoints() вернуть копию вектора трехмерных точек вместо ссылки:

// In class Tracker:
vector<Eigen::Vector3d> Tracker::getAllPoints()
{
    boost::mutex::scoped_lock lock(optotrakResourceMutex);
    return points; // Will call the std::vector() copy constructor
}

// In your main application:
void timerFunc()
{
    Tracker* tracker = ...;            // Obtain a pointer to the tracker object
    vector< Eigen::Vector3d > myPoints = tracker->getAllPoints();
    //... operations on your own copy if points
}

Обратите внимание, как мьютекс инкапсулирован в Tracker класс и как timerFunc() не нужно беспокоиться об этом.

Также обратите внимание, как мьютекс блокируется только во время копирования. Копия списка трехмерных векторов, безусловно, будет быстрее, чем математические операции над ними.

Другие вопросы по тегам