AD |
Дата 19.9.2008, 11:01 |
|
Не знаю уж чего я там еще такого наваял, но пока вроде бы работает без багов! |
Tonal |
Дата 19.9.2008, 10:11 |
|
Извини, правда некогда разбираться. Но, если ты таки хочешь работать с потоками, стоит самому разобраться - я же твою прогу писать не буду. |
AD |
Дата 15.9.2008, 11:14 |
|
Поправил немного. Но все-равно, работает кривовато. Причем глюки очень разнообразные: то график отображается параметра, который выбран не в данный момент, а во время предыдущей выборке, то совсем не отображается, то застревает на этапе выборки. Может быть сможете подсказать, где копнуть, чтобы поправить это безобразие?
GraphicDisplay::GraphicDisplay(QWidget *parent): QDialog(parent) { p_thread = new DTThread; }
GraphicDisplay::GraphicDisplay(QWidget *parent, ParamPlotSettings& st): QDialog(parent) { p_thread = new DTThread; }
GraphicDisplay::~GraphicDisplay() { delete rubber; delete contextMenu;
if(timer) { timer -> stop(); delete timer; } if(p_thread) { p_thread -> quit(); if(p_thread -> isRunning()) p_thread -> terminate(); delete p_thread; } }
/// Отрисовка графика void GraphicDisplay::paintEvent(QPaintEvent* events) { painter.begin(this);
painter.setWindow(paramsDisplay -> rect()); painter.setFont(QFont("Tahoma", 8, Qt::SolidLine)); painter.setPen(Qt::black);
if(gridAction -> isChecked()) drawGrid(&painter); drawCurves(&painter);
if(timer != 0) if(curveMap.size() == fact_prm.size()) timer -> stop();
painter.end(); }
/// Заполнение вектора данными void GraphicDisplay::fillCurve() { p_thread -> clearCurveMap(); p_thread -> rw_run.unlock(); }
/// Инициализация нужных для потока параметров void GraphicDisplay::initThread(QDialDistParam* pD, QDialTimeParam* pT, PlotSettings* sts) { p_thread -> mainWindow = mainWindow; p_thread -> pDist = pD; p_thread -> pTime = pT; p_thread -> settings = sts; p_thread -> CurveMap(curveMap);
p_thread -> rw_run.lockForRead(); p_thread -> start();
timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(forUpdate())); timer -> start(UPDATETIME); }
/// Обновление данных списка void GraphicDisplay::forUpdate() { if(p_thread -> rw_run.tryLockForRead()) { curveMap = p_thread -> CurveMap(); update(); } }
/// Закрытие окна void GraphicDisplay::closeEvent(QCloseEvent* events) { QDialog::closeEvent(events); if(p_thread) { if(p_thread -> isRunning()) p_thread -> terminate(); p_thread -> quit(); } if(timer) timer -> stop(); }
/// Запуск дополнительного потока void DTThread::run() { m_terminated.lock(); while(!w_terminated.wait(&m_terminated, 0)) { int id = 0; /// Заполнение данными по оси x fillXVec(data);
for(fact_param_iter fit=fact_prm.begin(); fit!=fact_prm.end(); ++fit, ++id) { m_terminated.unlock(); /// Заполнение данными по оси y ParamDescr* param_record = fit -> param_record; int index = 0; for(logI jter=mainWindow -> log.begin(); jter!=mainWindow -> log.end() && index!=data.size(); ++jter, ++index) { PARAMVALUE val = jter -> GetParamValue(&mainWindow -> cur_rec, param_record -> Name(), param_record -> Address()); data[index].setY(val.value); } curveMap.insert(id, data); m_terminated.lock(); } }
m_terminated.unlock(); exec(); }
|
AD |
Дата 12.9.2008, 16:52 |
|
Немного изменил. Все-равно ломается, во-первых, правда, в другом месте. Подскажите, пожалуйста, где ошибка. Правка произошла в функции run:
/// Запуск дополнительного потока void DTThread::run() { m_terminated.lock(); while(!w_terminated.wait(&m_terminated, 0)) { int id = 0; /// Заполнение данными по оси x fillXVec(data);
for(fact_param_iter fit=fact_prm.begin(); fit!=fact_prm.end(); ++fit, ++id) { /// Заполнение данными по оси y ParamDescr* param_record = fit -> param_record; int index = 0; for(logI jter=mainWindow -> log.begin(); jter!=mainWindow -> log.end() && index!=data.size(); ++jter, ++index) { PARAMVALUE val = jter -> GetParamValue(&mainWindow -> cur_rec, param_record -> Name(), param_record -> Address()); data[index].setY(val.value); } curveMap.insert(id, data); } }
w_terminated.wakeAll(); m_terminated.unlock(); exec(); }
Соответственно w_termainated.wakeAll() перенесена в run()! Я уже запутался, где ошибка. |
trdm |
Дата 12.9.2008, 13:39 |
|
Цитата(Tonal @ 12.9.2008, 13:03) Причём эту test4Update() дёргать или в идле, или по таймеру, пока не посчитается. а сигнал нельзя послать об окончании пересчета? |
AD |
Дата 12.9.2008, 13:26 |
|
Видимо, где-то напортачил, но вот где? Ломается с сообщением:
Цитата mutex must be unlocked in the same thread, that locked! Вот код:
/// Класс параллельного потока для заполнения данными кривых графика class DTThread: public QThread { Q_OBJECT
private: QMap<int, QVector<QPointF>> curveMap; ///< список изображаемых кривых
public: QPen myPen; ///< карандаш для рисования линий определенной жирности и цвета TLV* mainWindow; ///< указатель на главное окно QVector<QPointF> data; ///< вектор загружаемой кривой QDialDistParam* pDist; ///< указатель на класс диалога параметров по расстоянию QDialTimeParam* pTime; ///< указатель на класс диалога параметров по времени PlotSettings* settings; ///< указатель на настройку для определения масштаба QMutex m_terminated; ///< мьютекс для блокировки данных при работе с дополнительным потоком QWaitCondition w_terminated; ///< критическая секция для разблокировки мьютексов QReadWriteLock rw_run; ///< мьютекс для записи и чтения
private: void fillXVec(QVector<QPointF>& data);
protected: void run();
public: DTThread(): pDist(0), pTime(0), mainWindow(0) {} ~DTThread() {} QMap<int, QVector<QPointF>> CurveMap() { return curveMap; } void CurveMap(QMap<int, QVector<QPointF>> crv) { curveMap = crv; } void clearCurveMap() { curveMap.clear(); } void wake_all() { w_terminated.wakeAll(); } };
/// Запуск дополнительного потока void DTThread::run() { while(!w_terminated.wait(&m_terminated, 0)) { rw_run.lockForRead(); int id = 0; /// Заполнение данными по оси x fillXVec(data);
for(fact_param_iter fit=fact_prm.begin(); fit!=fact_prm.end(); ++fit, ++id) { /// Заполнение данными по оси y ParamDescr* param_record = fit -> param_record; int index = 0; for(logI jter=mainWindow -> log.begin(); jter!=mainWindow -> log.end() && index!=data.size(); ++jter, ++index) { PARAMVALUE val = jter -> GetParamValue(&mainWindow -> cur_rec, param_record -> Name(), param_record -> Address()); data[index].setY(val.value); } curveMap.insert(id, data); } }
exec(); }
/// Заполнение данными по оси x void DTThread::fillXVec(QVector<QPointF>& data) { double x = 0.0; ParamPlotSettings* p_set = (ParamPlotSettings*)settings; switch(p_set -> win_type) { case DISTPARAM: for(QVector<PARAMVALUE>::iterator iter=x_data.dist_x.begin(); iter!=x_data.dist_x.end(); ++iter) { x += (iter -> value / 1000.0); data.push_back(QPointF(x, 0.0)); int k = 0; switch(iter -> status) { case PS_FAIL: k = pDist -> spinFault -> text().toInt(); myPen.setWidth(k); break; case PS_NODATA: k = pDist -> spinNoData -> text().toInt(); myPen.setWidth(k); break; case PS_TEST: k = pDist -> spinTest -> text().toInt(); myPen.setWidth(k); break; case PS_OK: k = pDist -> spinNormal -> text().toInt(); myPen.setWidth(k); break; } } break; case TIMEPARAM: for(QVector<PARAMVALUE>::iterator iter=x_data.time_x.begin(); iter!=x_data.time_x.end(); ++iter) { x += (iter -> value / 60.0); data.push_back(QPointF(x, 0.0)); int k = 0; switch(iter -> status) { case PS_FAIL: k = pTime -> spinFault -> text().toInt(); myPen.setWidth(k); break; case PS_NODATA: k = pTime -> spinNoData -> text().toInt(); myPen.setWidth(k); break; case PS_TEST: k = pTime -> spinTest -> text().toInt(); myPen.setWidth(k); break; case PS_OK: k = pTime -> spinNormal -> text().toInt(); myPen.setWidth(k); break; } } break; } }
/// Заполнение вектора данными void GraphicDisplay::fillCurve() { p_thread -> clearCurveMap(); p_thread -> rw_run.unlock(); }
/// Инициализация нужных для потока параметров void GraphicDisplay::initThread(QDialDistParam* pD, QDialTimeParam* pT, PlotSettings* sts) { p_thread -> mainWindow = mainWindow; p_thread -> pDist = pD; p_thread -> pTime = pT; p_thread -> settings = sts; p_thread -> CurveMap(curveMap);
p_thread -> rw_run.lockForRead(); p_thread -> start();
timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(forUpdate())); timer -> start(UPDATETIME); }
/// Обновление данных списка void GraphicDisplay::forUpdate() { if(p_thread -> rw_run.tryLockForRead()) { curveMap = p_thread -> CurveMap(); update(); } }
/// Заставить остановиться остальным процессам void GraphicDisplay::wake_all() { p_thread -> wake_all(); }
/// Нажатие на кнопку OK void QDialDistParam::btnOKClick() { ParamPlotSettings settings; settings.setMaxX(q_calc.maxDist, DISTPARAM); settings.setMinX(x_data.dist_x.front().value, DISTPARAM); double c_max = 10.0, c_min = 0.0; findMinMaxY(c_min, c_max); settings.setMinY(c_min); settings.setMaxY(c_max); settings.adjust();
graphic -> setPlotSettings(settings); graphic -> pDist = this; graphic -> retranslateHeader(graphic); graphic -> initThread(this, 0, &settings);
graphic -> fillCurve(); graphic -> wake_all(); graphic -> exec(); }
|
AD |
Дата 12.9.2008, 12:20 |
|
Ну и последний вопросик: А набросок примерно такой:
QWaitCondition w_terminated;QMutex m_terminated;QReadWriteLock rw_run;void DTThread::Run() { while(!w_terminated.wait(m_terminated, 0)) { QWriteLocker w_run(rw_run); //Здесь выполняем то, что у тебя было внутри if(!stopped) } }
Опечатка? Имелось в виду w_run.writeForLock()? У меня есть rw_run, который в классе объявлен, а w_run вообще локально. |
Tonal |
Дата 12.9.2008, 12:03 |
|
Я же написал, что нужно изменить - fillCurve() разбить на 2:
/// Заполнение вектора данными void GraphicDisplay::fillCurve() { p_thread ->clearCurveMap(); w_run.unlock(); } void GraphicDisplay::test4Update() if (w_run.tryLockForRead()) { curveMap = p_thread->getCurveMap(); update(); } }
Причём эту test4Update() дёргать или в идле, или по таймеру, пока не посчитается. Ну и данные curveMap сделать разные для основного потока и для рабочего. Иначе всё равно придётся ждать окончания генерации. |
AD |
Дата 12.9.2008, 11:40 |
|
Цитата(Tonal @ 12.9.2008, 12:29) Переходи на 4.4?
За набросок спасибо, буду разбираться.
Перейти на Qt 4.4 не могу. Коммерческая версия с интеграцией в Visual Studio 2005!
Цитата Ну и в конце приложения нужно w_terminated.wakeAll() сделать. Только смысла в этом всём нет, т.к. у тебя получается, что главный поток просто замерзает и ждёт окончания рабочего. Чтобы не замерзал, нужно fillCurve разбить ровно на 2 половины: 1 - начать пересчёт, 2 - проверить не посчиталось ли (tryLockForRead), и если посчиталось - обновится. Ну и данные и потока и главного окна должны быть разные в этом случае. НЕ, не хочу, чтобы все застывало. В итоге я сделать хочу именно так, чтобы он заполнял по-частям. Но а пока сделать версию, чтобы это заполнение целиком происходило в доп. потоке! То, что работает быстрее, уже проверил! Т.е. приведенный кусок использовать без всяких вэйт кондишен? Мьютекс я использовал уж так, для того, чтобы не забыть, что я планирую в итоге сделать! А щас, хочу, чтобы попросту, после того, как в потоке заполнилось все, оно сразу же отобразилось! |
Tonal |
Дата 12.9.2008, 11:29 |
|
Переходи на 4.4?
А набросок примерно такой:
QWaitCondition w_terminated; QMutex m_terminated; QReadWriteLock rw_run; void DTThread::Run() { while(!w_terminated.wait(m_terminated, 0)) { QWriteLocker w_run(rw_run); //Здесь выполняем то, что у тебя было внутри if(!stopped) } }
/// Инициализация нужных для потока параметров void GraphicDisplay::initThread(QDialDistParam* pD, QDialTimeParam* pT, PlotSettings* sts) { //Здесь старая инициализация w_run.lockForRead(); p_thread -> start(); }
/// Заполнение вектора данными void GraphicDisplay::fillCurve() { curveMap.clear(); w_run.unlock(); w_run.lockForRead(); update(); }
Ну и в конце приложения нужно w_terminated.wakeAll() сделать. Только смысла в этом всём нет, т.к. у тебя получается, что главный поток просто замерзает и ждёт окончания рабочего. Чтобы не замерзал, нужно fillCurve разбить ровно на 2 половины: 1 - начать пересчёт, 2 - проверить не посчиталось ли (tryLockForRead), и если посчиталось - обновится. Ну и данные и потока и главного окна должны быть разные в этом случае. |
Просмотр темы полностью (откроется в новом окне) |
|