Skip to content

Instantly share code, notes, and snippets.

@vprus
Last active October 30, 2015 07:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vprus/7bb55cc6c6a1d4bbd3c4 to your computer and use it in GitHub Desktop.
Save vprus/7bb55cc6c6a1d4bbd3c4 to your computer and use it in GitHub Desktop.
QFuture on top of boost::future, try 2
#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