Last active
October 30, 2015 07:04
-
-
Save vprus/7bb55cc6c6a1d4bbd3c4 to your computer and use it in GitHub Desktop.
QFuture on top of boost::future, try 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <QCoreApplication> | |
#include <QTimer> | |
#include <QDebug> | |
#include <QThread> | |
#define BOOST_THREAD_VERSION 4 | |
#define BOOST_THREAD_PROVIDES_FUTURE 1 | |
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION 1 | |
#define BOOST_THREAD_PROVIDES_EXECUTORS 1 | |
#define BOOST_ALL_NO_LIB | |
#pragma comment(lib, "libboost_thread-vc120-mt-gd-1_60.lib") | |
#pragma comment(lib, "libboost_system-vc120-mt-gd-1_60.lib") | |
#define _CPPUNWIND 1 | |
#undef BOOST_NO_EXCEPTIONS | |
#include <boost/thread/future.hpp> | |
#include <boost/system/error_code.hpp> | |
#include <type_traits> | |
using namespace boost; | |
class Executor : public QObject | |
{ | |
public: | |
template<class F> | |
void submit(F &w) | |
{ | |
qDebug() << "Executor called in thread " << QThread::currentThread(); | |
if (QThread::currentThread() == thread()) { | |
w(); | |
} else { | |
QTimer::singleShot(0, this, [w]() mutable { | |
w(); | |
}); | |
} | |
} | |
void close() { | |
} | |
bool closed() { | |
return false; | |
} | |
bool try_executing_one() { | |
Q_ASSERT("not implemented"); | |
return true; | |
} | |
template<class P> | |
void reshedule_until(const P &p) { | |
Q_ASSERT("not implemented"); | |
} | |
}; | |
template<typename T> | |
class QFuture | |
{ | |
public: | |
QFuture(boost::future<T> &&f, boost::executor_ptr_type executor) | |
: future(std::move(f)), executor(executor) | |
{} | |
QFuture(QFuture &&another) | |
: future(std::move(another.future)), executor(std::move(another.executor)) | |
{} | |
template<typename F> | |
QFuture<std::result_of_t<F(boost::future<T>)>> | |
then(F &&f) | |
{ | |
return QFuture<std::result_of_t<F(boost::future<T>)>>(future.then(*executor, std::move(f)), executor); | |
} | |
private: | |
boost::future<T> future; | |
boost::executor_ptr_type executor; | |
}; | |
class Task : public QObject | |
{ | |
public: | |
Task() | |
{ | |
} | |
QFuture<int> run() | |
{ | |
qDebug() << "Thread affinity: " << thread(); | |
QTimer::singleShot(1000, this, [this] { | |
qDebug() << "Value set in thread " << QThread::currentThread(); | |
p.set_value(10); | |
}); | |
boost::executor_ptr_type e(new boost::executor_adaptor<Executor>()); | |
return QFuture<int>(std::move(p.get_future()), e); | |
} | |
private: | |
boost::promise<int> p; | |
}; | |
class WorkerThread : public QThread | |
{ | |
public: | |
QFuture<int> doSomething() | |
{ | |
Task *t = new Task(); | |
t->moveToThread(this); | |
return t->run(); | |
// Leak t for this test code | |
} | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
try { | |
QCoreApplication a(argc, argv); | |
QThread *mainThread = QThread::currentThread(); | |
qDebug() << "Starting up, main thread " << QThread::currentThread(); | |
WorkerThread workerThread; | |
QFuture<int> f = workerThread.doSomething(); | |
f | |
.then([mainThread](future<int> x) { | |
int v = x.get(); | |
qDebug() << "Got future value " << v << " in thread " << QThread::currentThread(); | |
return v + 10.1; | |
}) | |
.then([mainThread](future<double> x) { | |
double v = x.get(); | |
qDebug() << "Got further future value " << v << " in thread " << QThread::currentThread(); | |
}) | |
; | |
workerThread.start(); | |
return a.exec(); | |
} | |
catch(const std::exception &e) { | |
qDebug() << e.what(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment