summaryrefslogtreecommitdiffstats
path: root/client/clientapi.h
diff options
context:
space:
mode:
Diffstat (limited to 'client/clientapi.h')
-rw-r--r--client/clientapi.h46
1 files changed, 30 insertions, 16 deletions
diff --git a/client/clientapi.h b/client/clientapi.h
index 662f96c..a0020af 100644
--- a/client/clientapi.h
+++ b/client/clientapi.h
@@ -7,48 +7,60 @@
7#include <QTimer> 7#include <QTimer>
8#include <QDebug> 8#include <QDebug>
9#include <QEventLoop> 9#include <QEventLoop>
10#include <QtConcurrent/QtConcurrentRun>
10#include <functional> 11#include <functional>
12#include "threadboundary.h"
11 13
12namespace async { 14namespace async {
13 //This should abstract if we execute from eventloop or in thread. 15 //This should abstract if we execute from eventloop or in thread.
14 //It supposed to allow the caller to finish the current method before executing the runner. 16 //It supposed to allow the caller to finish the current method before executing the runner.
15 void run(const std::function<void()> &runner) { 17 void run(const std::function<void()> &runner) {
16 //FIXME we should be using a Job instead of a timer 18 QtConcurrent::run(runner);
17 auto timer = new QTimer; 19
18 timer->setSingleShot(true); 20 // //FIXME we should be using a Job instead of a timer
19 QObject::connect(timer, &QTimer::timeout, runner); 21 // auto timer = new QTimer;
20 QObject::connect(timer, &QTimer::timeout, timer, &QObject::deleteLater); 22 // timer->setSingleShot(true);
21 timer->start(0); 23 // QObject::connect(timer, &QTimer::timeout, runner);
24 // QObject::connect(timer, &QTimer::timeout, timer, &QObject::deleteLater);
25 // timer->start(0);
22 }; 26 };
23 27
24 /** 28 /**
25 * Query result set 29 * Query result set
26 *
27 * This should probably become part of a generic kasync library.
28 *
29 * Functional is nice because we don't have to store data in the emitter
30 * Non functional and storing may be the right thing because we want an in-memory representation of the set
31 * non-functional also allows us to batch move data across thread boundaries.
32 */ 30 */
33 31
34 template<class T> 32 template<class T>
35 class ResultEmitter; 33 class ResultEmitter;
36 34
37 /* 35 /*
38 * The promise side for the result provider 36 * The promise side for the result emitter
39 */ 37 */
40 template<class T> 38 template<class T>
41 class ResultProvider { 39 class ResultProvider {
42 public: 40 public:
41 //Called from worker thread
43 void add(const T &value) 42 void add(const T &value)
44 { 43 {
45 //the handler will be called in the other thread, protect 44 //We use the eventloop to call the addHandler directly from the main eventloop.
46 mResultEmitter->addHandler(value); 45 //That way the result emitter implementation doesn't have to care about threadsafety at all.
46 //The alternative would be to make all handlers of the emitter threadsafe.
47 auto emitter = mResultEmitter;
48 mResultEmitter->mThreadBoundary.callInMainThread([emitter, value]() {
49 if (emitter) {
50 emitter->addHandler(value);
51 }
52 });
47 } 53 }
48 54
55 //Called from worker thread
49 void complete() 56 void complete()
50 { 57 {
51 mResultEmitter->completeHandler(); 58 auto emitter = mResultEmitter;
59 mResultEmitter->mThreadBoundary.callInMainThread([emitter]() {
60 if (emitter) {
61 emitter->completeHandler();
62 }
63 });
52 } 64 }
53 65
54 QSharedPointer<ResultEmitter<T> > emitter() 66 QSharedPointer<ResultEmitter<T> > emitter()
@@ -92,6 +104,7 @@ namespace async {
92 std::function<void(const DomainType&)> addHandler; 104 std::function<void(const DomainType&)> addHandler;
93 // std::function<void(const T&)> removeHandler; 105 // std::function<void(const T&)> removeHandler;
94 std::function<void(void)> completeHandler; 106 std::function<void(void)> completeHandler;
107 ThreadBoundary mThreadBoundary;
95 }; 108 };
96 109
97 110
@@ -348,6 +361,7 @@ public:
348 async::run([resultSet, query](){ 361 async::run([resultSet, query](){
349 // Query all resources and aggregate results 362 // Query all resources and aggregate results
350 // query tells us in which resources we're interested 363 // query tells us in which resources we're interested
364 // TODO: queries to individual resources could be parallelized
351 for(const QString &resource : query.resources) { 365 for(const QString &resource : query.resources) {
352 auto facade = FacadeFactory::instance().getFacade<DomainType>(resource); 366 auto facade = FacadeFactory::instance().getFacade<DomainType>(resource);
353 //We have to bind an instance to the function callback. Since we use a shared pointer this keeps the result provider instance (and thus also the emitter) alive. 367 //We have to bind an instance to the function callback. Since we use a shared pointer this keeps the result provider instance (and thus also the emitter) alive.