From 5d3ed2294fcbda27bb78e8da4875acbda30f1eb5 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Fri, 31 Aug 2018 18:20:47 +0200 Subject: [PATCH] initial --- DataService.pro | 48 +++++++ DataService.pro.user | 336 +++++++++++++++++++++++++++++++++++++++++++ converttoseries.cpp | 26 ++++ converttoseries.h | 33 +++++ dataloader.cpp | 16 +++ dataloader.h | 20 +++ dataqueue.cpp | 54 +++++++ dataqueue.h | 42 ++++++ datarequest.cpp | 5 + datarequest.h | 16 +++ dataresult1d.cpp | 6 + dataresult1d.h | 18 +++ dataservice.cpp | 20 +++ dataservice.h | 19 +++ main.cpp | 13 ++ mainwindow.cpp | 107 ++++++++++++++ mainwindow.h | 46 ++++++ mainwindow.ui | 57 ++++++++ 18 files changed, 882 insertions(+) create mode 100644 DataService.pro create mode 100644 DataService.pro.user create mode 100644 converttoseries.cpp create mode 100644 converttoseries.h create mode 100644 dataloader.cpp create mode 100644 dataloader.h create mode 100644 dataqueue.cpp create mode 100644 dataqueue.h create mode 100644 datarequest.cpp create mode 100644 datarequest.h create mode 100644 dataresult1d.cpp create mode 100644 dataresult1d.h create mode 100644 dataservice.cpp create mode 100644 dataservice.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui diff --git a/DataService.pro b/DataService.pro new file mode 100644 index 0000000..7d9cd69 --- /dev/null +++ b/DataService.pro @@ -0,0 +1,48 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-08-29T14:47:02 +# +#------------------------------------------------- + +QT += core gui charts + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = DataService +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + dataservice.cpp \ + dataqueue.cpp \ + dataloader.cpp \ + dataresult1d.cpp \ + datarequest.cpp \ + converttoseries.cpp + +HEADERS += \ + mainwindow.h \ + dataservice.h \ + dataqueue.h \ + dataloader.h \ + dataresult1d.h \ + datarequest.h \ + converttoseries.h + +FORMS += \ + mainwindow.ui + +unix|win32: LIBS += -lnix diff --git a/DataService.pro.user b/DataService.pro.user new file mode 100644 index 0000000..b1cea73 --- /dev/null +++ b/DataService.pro.user @@ -0,0 +1,336 @@ + + + + + + EnvironmentId + {8b523b8d-f5ce-4be4-a9bd-780a0aec766f} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {d7263c99-5355-4486-be71-56523c5d259f} + 0 + 0 + 0 + + /home/grewe/zwischenlager/event_queue/build-DataService-Desktop-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/grewe/zwischenlager/event_queue/build-DataService-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /home/grewe/zwischenlager/event_queue/build-DataService-Desktop-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + DataService + + Qt4ProjectManager.Qt4RunConfiguration:/home/grewe/zwischenlager/event_queue/DataService/DataService.pro + true + + DataService.pro + false + + /home/grewe/zwischenlager/event_queue/build-DataService-Desktop-Debug + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/converttoseries.cpp b/converttoseries.cpp new file mode 100644 index 0000000..a539292 --- /dev/null +++ b/converttoseries.cpp @@ -0,0 +1,26 @@ +#include "converttoseries.h" +using namespace QtCharts; + +ConvertToSeries::ConvertToSeries(QObject *parent) : QObject(parent) +{ + +} + +void ConvertToSeries::run() { + mutex.lock(); + if (dataPresent) { + for (size_t i = 0; i < data.xdata.size(); ++i) { + this->series->append(data.xdata[i], data.ydata[i]); + } + emit dataConverted(series, QString::fromStdString(data.entityId)); + } + mutex.unlock(); +} + +void ConvertToSeries::setData(QLineSeries *series, const DataResult1D &data) { + mutex.lock(); + this->series = series; + this->data = data; + this->dataPresent = true; + mutex.unlock(); +} diff --git a/converttoseries.h b/converttoseries.h new file mode 100644 index 0000000..97d19e5 --- /dev/null +++ b/converttoseries.h @@ -0,0 +1,33 @@ +#ifndef CONVERTTOSERIES_H +#define CONVERTTOSERIES_H + +#include +#include +#include +#include +#include "dataresult1d.h" + +using namespace QtCharts; + +class ConvertToSeries : public QObject, public QRunnable { + Q_OBJECT +public: + explicit ConvertToSeries(QObject *parent = nullptr); + +private: + QMutex mutex; + bool dataPresent = false; + DataResult1D data; + QLineSeries *series; + + void run() override; + +public: + void setData(QLineSeries *series, const DataResult1D &data); + +signals: + void dataConverted(QLineSeries *series, QString entityId); + +}; + +#endif // CONVERTTOSERIES_H diff --git a/dataloader.cpp b/dataloader.cpp new file mode 100644 index 0000000..a2c42d8 --- /dev/null +++ b/dataloader.cpp @@ -0,0 +1,16 @@ +#include "dataloader.h" +#include + +DataLoader::DataLoader() +{ + +} + +DataResult1D DataLoader::doLoad(const DataRequest &request) { + std::vector x, y; + x = request.array.getDimension(1).asSampledDimension().axis(request.count[0], request.start[0]); + request.array.getData(y, request.count, request.start); + + DataResult1D res(request.id, request.array.id(), x, y); + return res; +} diff --git a/dataloader.h b/dataloader.h new file mode 100644 index 0000000..cf4b085 --- /dev/null +++ b/dataloader.h @@ -0,0 +1,20 @@ +#ifndef DATALOADER_H +#define DATALOADER_H + +#include +#include "datarequest.h" +#include "dataresult1d.h" + +class DataLoader : public QObject +{ + Q_OBJECT +public: + DataLoader(); + +public slots: + DataResult1D doLoad(const DataRequest &request); +}; + + + +#endif // DATALOADER_H diff --git a/dataqueue.cpp b/dataqueue.cpp new file mode 100644 index 0000000..ed5fa43 --- /dev/null +++ b/dataqueue.cpp @@ -0,0 +1,54 @@ +#include "dataqueue.h" + + +DataQueue::DataQueue(QObject *parent) : + QThread(parent), stopped(false) +{} + + +DataQueue::~DataQueue(){ +} + +void DataQueue::run() { + mutex.lock(); + bool stop = stopped || (requestQueue.size() == 0); + mutex.unlock(); + while (!stop) { + mutex.lock(); + if (requestQueue.size() > 0) { + DataResult1D data = loader->doLoad(requestQueue.front()); + resultMap.insert(std::pair(data.id, data)); + emit resultReady(QString::fromStdString(data.id)); + requestQueue.pop(); + stop = requestQueue.size() == 0 || stopped; + } + mutex.unlock(); + } +} + +void DataQueue::requestData(const nix::DataArray &array, const nix::NDSize &count, const nix::NDSize &offset, std::string &requestId) { + requestId = nix::util::createId(); + DataRequest dr(requestId, array, count, offset); + mutex.lock(); + requestQueue.push(dr); + mutex.unlock(); + start(); +} + +void DataQueue::stop() { + mutex.lock(); + stopped = true; + mutex.unlock(); +} + +DataResult1D DataQueue::getData(QString requestId) { + DataResult1D ret; + mutex.lock(); + std::map::iterator it = resultMap.find(requestId.toStdString()); + if (it != resultMap.end()) { + ret = it->second; + resultMap.erase(it); + } + mutex.unlock(); + return ret; +} diff --git a/dataqueue.h b/dataqueue.h new file mode 100644 index 0000000..a583253 --- /dev/null +++ b/dataqueue.h @@ -0,0 +1,42 @@ +#ifndef DATAQUEUE_H +#define DATAQUEUE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "dataloader.h" +#include "dataresult1d.h" +#include "datarequest.h" + +class DataQueue : public QThread +{ + Q_OBJECT +public: + DataQueue(QObject *parent = 0); + ~DataQueue(); + + void run() override; + void stop(); + DataResult1D getData(QString requestId); + +signals: + void resultReady(QString requestId); + +public slots: + void requestData(const nix::DataArray &array, const nix::NDSize &count, const nix::NDSize &offset, std::string &requestId); + + +private: + std::queue requestQueue; + std::map resultMap; + QMutex mutex; + DataLoader *loader; + bool stopped; +}; + +#endif // DATAQUEUE_H diff --git a/datarequest.cpp b/datarequest.cpp new file mode 100644 index 0000000..3a6cbd1 --- /dev/null +++ b/datarequest.cpp @@ -0,0 +1,5 @@ +#include "datarequest.h" + +DataRequest::DataRequest(const std::string &requestId, const nix::DataArray &array, const nix::NDSize &count, const nix::NDSize &start) + : id(requestId), array(array), count(count), start(start) +{} diff --git a/datarequest.h b/datarequest.h new file mode 100644 index 0000000..e051568 --- /dev/null +++ b/datarequest.h @@ -0,0 +1,16 @@ +#ifndef DATAREQUEST_H +#define DATAREQUEST_H + +#include + +class DataRequest +{ +public: + DataRequest(const std::string &requestId, const nix::DataArray &array, const nix::NDSize &count, const nix::NDSize &start); + + std::string id; + nix::DataArray array; + nix::NDSize count, start; +}; + +#endif // DATAREQUEST_H diff --git a/dataresult1d.cpp b/dataresult1d.cpp new file mode 100644 index 0000000..0a87513 --- /dev/null +++ b/dataresult1d.cpp @@ -0,0 +1,6 @@ +#include "dataresult1d.h" + +DataResult1D::DataResult1D(const std::string &request_id, const std::string &entityId, const std::vector &x, const std::vector &y) + : id(request_id), entityId(entityId), xdata(x), ydata(y) +{} + diff --git a/dataresult1d.h b/dataresult1d.h new file mode 100644 index 0000000..baa5fdd --- /dev/null +++ b/dataresult1d.h @@ -0,0 +1,18 @@ +#ifndef DATARESULT1D_H +#define DATARESULT1D_H + +#include +#include + +class DataResult1D +{ +public: + DataResult1D(){}; + DataResult1D(const std::string &request_id, const std::string &entityId, const std::vector &x, const std::vector &y); + + std::string id, entityId; + std::vector xdata; + std::vector ydata; +}; + +#endif // DATARESULT1D_H diff --git a/dataservice.cpp b/dataservice.cpp new file mode 100644 index 0000000..2e5b660 --- /dev/null +++ b/dataservice.cpp @@ -0,0 +1,20 @@ +#include "dataservice.h" + + +DataService::DataService(QObject *parent): + QObject(parent) +{} + + +void DataService::doWork( ) { + QString result; + size_t count = 0; + for (size_t i = 1; i < 100000000; ++i){ + count++; + } + + /* ... here is the expensive or blocking operation ... */ + emit resultReady(); +} + + diff --git a/dataservice.h b/dataservice.h new file mode 100644 index 0000000..6dc75a7 --- /dev/null +++ b/dataservice.h @@ -0,0 +1,19 @@ +#ifndef DATASERVICE_H +#define DATASERVICE_H + +#include + +class DataService : public QObject +{ + Q_OBJECT +public: + explicit DataService(QObject *parent = nullptr); + +signals: + void resultReady(); + +public slots: + void doWork(); +}; + +#endif // DATASERVICE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..4cc5943 --- /dev/null +++ b/main.cpp @@ -0,0 +1,13 @@ +#include "mainwindow.h" +#include +#include "dataresult1d.h" + + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..05c9ca3 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,107 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "converttoseries.h" +#include + +using namespace QtCharts; + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + /* + dataService = new DataService(); + dataService->moveToThread(&dataServiceThread); + connect(&dataServiceThread, &QThread::finished, dataService, &QObject::deleteLater); + connect(ui->goBtn, SIGNAL(clicked(bool)), dataService, SLOT(doWork())); + connect(dataService, SIGNAL(resultReady()), this, SLOT(handleResult())); + dataServiceThread.start(); + */ + connect(&dataQueue, SIGNAL(resultReady(QString)), this, SLOT(dataReady(QString))); + //connect(&dataQueue, SIGNAL(finished()), &dataQueue, SLOT(deleteLater())); + DataLoader *loader = new DataLoader(); + loader->moveToThread(&dataQueue); + dataQueue.start(); + + connect(ui->requestDataBtn, SIGNAL(clicked(bool)), this, SLOT(requestData())); + file = nix::File::open("/home/grewe/zwischenlager/2017-08-17-af-invivo-1/2017-08-17-af-invivo-1.nix", + nix::FileMode::ReadOnly); + + //file = nix::File::open("/Users/jan/zwischenlager/threading_test/event_queue/DataService/data/2017-08-17-af-invivo-1.nix", + // nix::FileMode::ReadOnly); + nix::Block b = file.getBlock(0); + this->voltage = b.getDataArray("V-1"); + this->eod = b.getDataArray("EOD"); + + voltageChart = new QChart(); + voltageChart->legend()->hide(); + //voltageChart->createDefaultAxes(); + + eodChart = new QChart(); + eodChart->legend()->hide(); + //eodChart->createDefaultAxes(); + + + chartMap.insert(std::pair(voltage.id(), voltageChart)); + chartMap.insert(std::pair(eod.id(), eodChart)); + + voltageChart->setTitle(QString::fromStdString(this->voltage.name())); + eodChart->setTitle(QString::fromStdString(this->eod.name())); + QMargins margins = voltageChart->margins(); + int marg1 = margins.left(); + margins.setLeft(marg1 * 4); + eodChart->setMargins(margins); + voltageView = new QtCharts::QChartView(voltageChart); + eodView = new QtCharts::QChartView(eodChart); + + voltageView->setRenderHint(QPainter::Antialiasing); + eodView->setRenderHint(QPainter::Antialiasing); + ui->vbox->addWidget(voltageView); + ui->vbox->addWidget(eodView); +} + + +MainWindow::~MainWindow() { + if (file) { + file.close(); + } + //dataServiceThread.quit(); + //dataServiceThread.wait(); + dataQueue.stop(); + dataQueue.quit(); + dataQueue.wait(); + delete ui; +} + + +void MainWindow::dataReady(QString requestId) { + DataResult1D data = dataQueue.getData(requestId); + if (data.id.empty()) { + return; + } + ConvertToSeries *task = new ConvertToSeries(); + QLineSeries *series = new QLineSeries(); + task->setData(series, data); + connect(task, SIGNAL(dataConverted(QLineSeries*,QString)), this, SLOT(dataConverted(QLineSeries*,QString))); + QThreadPool::globalInstance()->start(task); +} + + +void MainWindow::dataConverted(QLineSeries *series, QString entityId) { + QPen pen = series->pen(); + pen.setWidth(1); + series->setPen(pen); + chartMap[entityId.toStdString()]->addSeries(series); +} + + +void MainWindow::requestData() { + if (voltage && eod) { + nix::NDSize count(1, 10000); + nix::NDSize start(1, 0); + std::string vId, eodId; + dataQueue.requestData(voltage, count, start, vId); + dataQueue.requestData(eod, count, start, eodId); + } +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..506e7f1 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,46 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +//#include +#include +#include + +#include "dataservice.h" +#include "dataqueue.h" +#include "dataresult1d.h" + +Q_DECLARE_METATYPE(DataResult1D) + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +public slots: + void requestData(); + void dataReady(QString requestId); + void dataConverted(QLineSeries *series, QString entityId); + +private: + Ui::MainWindow *ui; + //QThread dataServiceThread; + //DataService *dataService; + DataQueue dataQueue; + nix::DataArray voltage, eod; + nix::File file; + QtCharts::QChartView *voltageView; + QtCharts::QChartView *eodView; + QtCharts::QChart *voltageChart; + QtCharts::QChart *eodChart; + std::map chartMap; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..8b45b0c --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,57 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + 2 + + + + + + + request data + + + + + + + + + 0 + 0 + 400 + 28 + + + + + + TopToolBarArea + + + false + + + + + + + +