Добрый день.
Мы используем Gis Designer версии 11.10.7 под Astra Linux SE 1.4. Среда разработки Qt Creator.
Столкнулись со следующей проблемой. При использовании функций mapGetHeightValue или mapGetHeightArray в не основном потоке часто происходит зависание
потока, либо в последствии возникают наведенные ошибки (Вроде повисания процесса отрисовки карты). При чтении рельефа мы используем мьютексы.
Причем, если теже самые действия выполнять в основном потоке (Где отрисовывается GUI-интерфейс), то все нормально.
Урезали нашу задачу до маленького примера, где подобные глюки возникают всегда, даже если все выполнять все в одном, но не основном потоке. Карта масштаба 1 : 50000 и состоит из 350 листов.
Матрица высот расчитана с дискретом в 50 м. Если не вызыватть функцию mapGetHeightValue, то глюки пропадают.
В связи с этим вопрос: Как осуществлять параллельное считывание рельефа? Поддерживает ли функция mapGetHeightArray работу в множестве потоков?
Прилагаю пример кода:
Заголовочный файл calcMap.h:
[CODE]#include <QApplication>
#include <QVector>
#include <QList>
#include <QRunnable>
#include <QThread>
#include <QMutex>
#include <ma th.h>
#include <QDebug>
#ifndef MAP_API_H
#include <mapapi.h>
#endif
using namespace std;
class informVyr {
private:
public:
informVyr() {}
~informVyr() {}
QMutex *hMut_ptr;
QString pathToMap;
HMAP hmap;
double Xstart; // Координаты начала матрицы
double Ystart;
double dsk; // дискрет
QVector <QVector <double> > masIfo;
void testVyr(int numL, int kolL);
};
// Класс расчета
class calcMap {
private:
public:
calcMap(QString Mappath);
~calcMap();
informVyr MIV;
};
// Класс параллельной обработки
class parInf : public QThread {
private:
informVyr *MIV;
int numL; // Номер среза
int kolL; // кол-во срезов
public:
parInf(informVyr *MIV, int numL, int kolL);
void run();
};[/CODE]
Файл calcMap.cpp:
[CODE]#include "calcMap.h"
calcMap::calcMap(QString Mappath) {
QMutex infMut;
MIV.hMut_ptr = &infMut;
MIV.pathToMap = Mappath; // Путь к карте
MIV.hmap = mapOpenMap(Mappath.toStdString().c_str(), GENERIC_READ);
if (!MIV.hmap)
return;
// Путь к матрице высот (Должна лежать в каталоге с картой и иметь такое же имя)
string pathMtw = Mappath.toStdString();
pathMtw = pathMtw.substr(0, pathMtw.length()-4);
pathMtw += ".mtw";
qDebug() << "\nПодключение матрицы высот";
if (!mapOpenMtrForMap( MIV.hmap, pathMtw.c_str(), GENERIC_READ))
return;
double dsk = 4000; // Дискрет
// Расчет кол-ва элементов матрицы
int cou = mapGetMtrCount(MIV.hmap);
MTRDESCRIBE desc;
mapGetMtrDescribe(MIV.hmap, 1, &desc);
// Граничные точки матрицы
double X1 = desc.FrameMeters.X1;
double Y1 = desc.FrameMeters.Y1;
double X2 = desc.FrameMeters.X2;
double Y2 = desc.FrameMeters.Y2;
for (int i = 2; i <= cou; i++) {
mapGetMtrDescribe(MIV.hmap, i, &desc);
if (desc.FrameMeters.X1 < X1)
X1 = desc.FrameMeters.X1;
if (desc.FrameMeters.Y1 < Y1)
Y1 = desc.FrameMeters.Y1;
if (desc.FrameMeters.X2 > X2)
X2 = desc.FrameMeters.X2;
if (desc.FrameMeters.Y2 > Y2)
Y2 = desc.FrameMeters.Y2;
}
int xCou = ceil((X2 - X1)/dsk);
int yCou = ceil((Y2 - Y1)/dsk);
X2 = X1 + xCou*dsk;
Y2 = Y1 + yCou*dsk;
qDebug() << "\nМатрица:" << xCou << yCou;
// Формирование матрицы
MIV.masIfo.clear();
MIV.masIfo.resize(xCou);
for (int i=0 ; i < xCou; i++) {
MIV.masIfo[i].resize(yCou);
for (int j=0; j < yCou; j++)
MIV.masIfo[i][j] = 0; // Зануление
}
// Инициализация параметров
MIV.Xstart = X1;
MIV.Ystart = Y1;
MIV.dsk = dsk;
int kolL = QThread::idealThreadCount(); // Кол-во параллельных процессов
if (kolL < 1)
kolL = 1;
bool ParalPro = true; // Признак распараллеливания
kolL = 1; // Принудительная установка 1 потока
qDebug() << "Кол-во процессов" << kolL;
if (!ParalPro) {
qDebug() << "\nПоследовательный расчет";
for (int i = 0; i < kolL; i++)
MIV.testVyr(i, kolL);
} else {
qDebug() << "\nПараллельный расчет по линиям";
// Массив обрабатывющих потоков
QVector <parInf*> masThread;
masThread.resize(kolL);
// Создание потоков
for (int i = 0; i < kolL; i++)
masThread[i] = new parInf(&MIV, i, kolL);
// Запуск потоков
for (int i = 0; i < kolL; i++)
masThread[i]->start();
int activeTCou = kolL;
// Ожидание завершения всех потоков
while (activeTCou > 0) {
activeTCou = 0;
for (int i = 0; i < kolL; i++) // Подсчет текущих потоков
if (masThread[i]->isRunning())
activeTCou++;
}
// Удаление потоков
for (int i = 0; i < kolL; i++) {
delete masThread[i];
}
}
mapCloseMap(MIV.hmap); // Закрытие карты
return;
}
calcMap::~calcMap() { }
// Распараллеливание
parInf::parInf(informVyr *MIV, int numL, int kolL) : QThread() {
this->MIV = MIV;
this->numL = numL;
this->kolL = kolL;;
}
void parInf::run() {
MIV->testVyr(numL, kolL);
}
void informVyr::testVyr(int numL, int kolL) {
qDebug() << "\nНачало расчета среза линий №" << numL;
int begL = 0;
int endL = masIfo.size();
if (numL != -1) { // Если задан номер среза
begL = numL*masIfo.size()/kolL;
endL = (numL+1)*masIfo.size()/kolL;
if (numL == kolL-1) // Если срез последний
endL = masIfo.size(); // Конец массива
}
qDebug() << "От" << begL << " До" << endL;
for (int i = begL; i < endL; i++) {
if (i%5 == 0)
qDebug() << "i = " << i;
for (int j = 0; j < masIfo[i].size(); j++) {
hMut_ptr->lock();
mapGetHeightValue(hmap, Xstart + dsk*i, Ystart + dsk*j);
hMut_ptr->unlock();
}
}
qDebug() << "\nКонец расчета среза линий" << numL;
return;
}[/CODE]
Мы используем Gis Designer версии 11.10.7 под Astra Linux SE 1.4. Среда разработки Qt Creator.
Столкнулись со следующей проблемой. При использовании функций mapGetHeightValue или mapGetHeightArray в не основном потоке часто происходит зависание
потока, либо в последствии возникают наведенные ошибки (Вроде повисания процесса отрисовки карты). При чтении рельефа мы используем мьютексы.
Причем, если теже самые действия выполнять в основном потоке (Где отрисовывается GUI-интерфейс), то все нормально.
Урезали нашу задачу до маленького примера, где подобные глюки возникают всегда, даже если все выполнять все в одном, но не основном потоке. Карта масштаба 1 : 50000 и состоит из 350 листов.
Матрица высот расчитана с дискретом в 50 м. Если не вызыватть функцию mapGetHeightValue, то глюки пропадают.
В связи с этим вопрос: Как осуществлять параллельное считывание рельефа? Поддерживает ли функция mapGetHeightArray работу в множестве потоков?
Прилагаю пример кода:
Заголовочный файл calcMap.h:
[CODE]#include <QApplication>
#include <QVector>
#include <QList>
#include <QRunnable>
#include <QThread>
#include <QMutex>
#include <ma th.h>
#include <QDebug>
#ifndef MAP_API_H
#include <mapapi.h>
#endif
using namespace std;
class informVyr {
private:
public:
informVyr() {}
~informVyr() {}
QMutex *hMut_ptr;
QString pathToMap;
HMAP hmap;
double Xstart; // Координаты начала матрицы
double Ystart;
double dsk; // дискрет
QVector <QVector <double> > masIfo;
void testVyr(int numL, int kolL);
};
// Класс расчета
class calcMap {
private:
public:
calcMap(QString Mappath);
~calcMap();
informVyr MIV;
};
// Класс параллельной обработки
class parInf : public QThread {
private:
informVyr *MIV;
int numL; // Номер среза
int kolL; // кол-во срезов
public:
parInf(informVyr *MIV, int numL, int kolL);
void run();
};[/CODE]
Файл calcMap.cpp:
[CODE]#include "calcMap.h"
calcMap::calcMap(QString Mappath) {
QMutex infMut;
MIV.hMut_ptr = &infMut;
MIV.pathToMap = Mappath; // Путь к карте
MIV.hmap = mapOpenMap(Mappath.toStdString().c_str(), GENERIC_READ);
if (!MIV.hmap)
return;
// Путь к матрице высот (Должна лежать в каталоге с картой и иметь такое же имя)
string pathMtw = Mappath.toStdString();
pathMtw = pathMtw.substr(0, pathMtw.length()-4);
pathMtw += ".mtw";
qDebug() << "\nПодключение матрицы высот";
if (!mapOpenMtrForMap( MIV.hmap, pathMtw.c_str(), GENERIC_READ))
return;
double dsk = 4000; // Дискрет
// Расчет кол-ва элементов матрицы
int cou = mapGetMtrCount(MIV.hmap);
MTRDESCRIBE desc;
mapGetMtrDescribe(MIV.hmap, 1, &desc);
// Граничные точки матрицы
double X1 = desc.FrameMeters.X1;
double Y1 = desc.FrameMeters.Y1;
double X2 = desc.FrameMeters.X2;
double Y2 = desc.FrameMeters.Y2;
for (int i = 2; i <= cou; i++) {
mapGetMtrDescribe(MIV.hmap, i, &desc);
if (desc.FrameMeters.X1 < X1)
X1 = desc.FrameMeters.X1;
if (desc.FrameMeters.Y1 < Y1)
Y1 = desc.FrameMeters.Y1;
if (desc.FrameMeters.X2 > X2)
X2 = desc.FrameMeters.X2;
if (desc.FrameMeters.Y2 > Y2)
Y2 = desc.FrameMeters.Y2;
}
int xCou = ceil((X2 - X1)/dsk);
int yCou = ceil((Y2 - Y1)/dsk);
X2 = X1 + xCou*dsk;
Y2 = Y1 + yCou*dsk;
qDebug() << "\nМатрица:" << xCou << yCou;
// Формирование матрицы
MIV.masIfo.clear();
MIV.masIfo.resize(xCou);
for (int i=0 ; i < xCou; i++) {
MIV.masIfo[i].resize(yCou);
for (int j=0; j < yCou; j++)
MIV.masIfo[i][j] = 0; // Зануление
}
// Инициализация параметров
MIV.Xstart = X1;
MIV.Ystart = Y1;
MIV.dsk = dsk;
int kolL = QThread::idealThreadCount(); // Кол-во параллельных процессов
if (kolL < 1)
kolL = 1;
bool ParalPro = true; // Признак распараллеливания
kolL = 1; // Принудительная установка 1 потока
qDebug() << "Кол-во процессов" << kolL;
if (!ParalPro) {
qDebug() << "\nПоследовательный расчет";
for (int i = 0; i < kolL; i++)
MIV.testVyr(i, kolL);
} else {
qDebug() << "\nПараллельный расчет по линиям";
// Массив обрабатывющих потоков
QVector <parInf*> masThread;
masThread.resize(kolL);
// Создание потоков
for (int i = 0; i < kolL; i++)
masThread[i] = new parInf(&MIV, i, kolL);
// Запуск потоков
for (int i = 0; i < kolL; i++)
masThread[i]->start();
int activeTCou = kolL;
// Ожидание завершения всех потоков
while (activeTCou > 0) {
activeTCou = 0;
for (int i = 0; i < kolL; i++) // Подсчет текущих потоков
if (masThread[i]->isRunning())
activeTCou++;
}
// Удаление потоков
for (int i = 0; i < kolL; i++) {
delete masThread[i];
}
}
mapCloseMap(MIV.hmap); // Закрытие карты
return;
}
calcMap::~calcMap() { }
// Распараллеливание
parInf::parInf(informVyr *MIV, int numL, int kolL) : QThread() {
this->MIV = MIV;
this->numL = numL;
this->kolL = kolL;;
}
void parInf::run() {
MIV->testVyr(numL, kolL);
}
void informVyr::testVyr(int numL, int kolL) {
qDebug() << "\nНачало расчета среза линий №" << numL;
int begL = 0;
int endL = masIfo.size();
if (numL != -1) { // Если задан номер среза
begL = numL*masIfo.size()/kolL;
endL = (numL+1)*masIfo.size()/kolL;
if (numL == kolL-1) // Если срез последний
endL = masIfo.size(); // Конец массива
}
qDebug() << "От" << begL << " До" << endL;
for (int i = begL; i < endL; i++) {
if (i%5 == 0)
qDebug() << "i = " << i;
for (int j = 0; j < masIfo[i].size(); j++) {
hMut_ptr->lock();
mapGetHeightValue(hmap, Xstart + dsk*i, Ystart + dsk*j);
hMut_ptr->unlock();
}
}
qDebug() << "\nКонец расчета среза линий" << numL;
return;
}[/CODE]