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()
не нужно беспокоиться об этом.
Также обратите внимание, как мьютекс блокируется только во время копирования. Копия списка трехмерных векторов, безусловно, будет быстрее, чем математические операции над ними.