/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #ifndef RUNEXTENSIONS_H #define RUNEXTENSIONS_H #include "qtcassert.h" #include "utils_global.h" #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { template class StoredInterfaceFunctionCall0 : public QRunnable { public: StoredInterfaceFunctionCall0(const FunctionPointer &fn) : fn(fn) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; }; template class StoredInterfaceMemberFunctionCall0 : public QRunnable { public: StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface &), Class *object) : fn(fn), object(object) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; }; template class StoredInterfaceFunctionCall1 : public QRunnable { public: StoredInterfaceFunctionCall1(void (fn)(QFutureInterface &, Arg1), const Arg1 &arg1) : fn(fn), arg1(arg1) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; }; template class StoredInterfaceMemberFunctionCall1 : public QRunnable { public: StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface &, Arg1), Class *object, const Arg1 &arg1) : fn(fn), object(object), arg1(arg1) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; }; template class StoredInterfaceFunctionCall2 : public QRunnable { public: StoredInterfaceFunctionCall2(void (fn)(QFutureInterface &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) : fn(fn), arg1(arg1), arg2(arg2) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; }; template class StoredInterfaceMemberFunctionCall2 : public QRunnable { public: StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) : fn(fn), object(object), arg1(arg1), arg2(arg2) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; }; template class StoredInterfaceFunctionCall3 : public QRunnable { public: StoredInterfaceFunctionCall3(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template class StoredInterfaceMemberFunctionCall3 : public QRunnable { public: StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template class StoredInterfaceFunctionCall4 : public QRunnable { public: StoredInterfaceFunctionCall4(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template class StoredInterfaceMemberFunctionCall4 : public QRunnable { public: StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template class StoredInterfaceFunctionCall5 : public QRunnable { public: StoredInterfaceFunctionCall5(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template class StoredInterfaceMemberFunctionCall5 : public QRunnable { public: StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template QFuture run(void (*functionPointer)(QFutureInterface &)) { return (new StoredInterfaceFunctionCall0 &)>(functionPointer))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1), const Arg1 &arg1) { return (new StoredInterfaceFunctionCall1 &, Arg1), Arg1>(functionPointer, arg1))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceFunctionCall2 &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceFunctionCall3 &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceFunctionCall4 &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceFunctionCall5 &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &), Class *object) { return (new StoredInterfaceMemberFunctionCall0 &), Class>(fn, object))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1), Class *object, Arg1 arg1) { return (new StoredInterfaceMemberFunctionCall1 &, Arg1), Class, Arg1>(fn, object, arg1))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceMemberFunctionCall2 &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceMemberFunctionCall3 &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceMemberFunctionCall4 &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceMemberFunctionCall5 &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(const std::function &)> &fn) { return (new StoredInterfaceFunctionCall0 &)>>(fn))->start(); } } // namespace QtConcurrent QT_END_NAMESPACE namespace Utils { template typename std::vector>::iterator waitForAny(std::vector> &futures) { // Wait for any future to have a result ready. // Unfortunately we have to do that in a busy loop because future doesn't have a feature to // wait for any of a set of futures (yet? possibly when_any in C++17). auto end = futures.end(); QTC_ASSERT(!futures.empty(), return end); auto futureIterator = futures.begin(); forever { if (futureIterator->wait_for(std::chrono::duration::zero()) == std::future_status::ready) return futureIterator; ++futureIterator; if (futureIterator == end) futureIterator = futures.begin(); } } namespace Internal { template void swapErase(std::vector &vec, typename std::vector::iterator it) { // efficient erasing by swapping with back element *it = std::move(vec.back()); vec.pop_back(); } template void reduceOne(QFutureInterface &futureInterface, std::vector> &futures, State &state, const ReduceFunction &reduce) { auto futureIterator = waitForAny(futures); if (futureIterator != futures.end()) { reduce(futureInterface, state, futureIterator->get()); swapErase(futures, futureIterator); } } // This together with reduceOne can be replaced by std::transformReduce (parallelism TS) // when that becomes widely available in C++ implementations template void mapReduceLoop(QFutureInterface &futureInterface, const Container &container, const MapFunction &map, State &state, const ReduceFunction &reduce) { const unsigned MAX_THREADS = std::thread::hardware_concurrency(); using MapResult = typename std::result_of,typename Container::value_type)>::type; std::vector> futures; futures.reserve(MAX_THREADS); auto fileIterator = container.begin(); auto end = container.end(); while (!futureInterface.isCanceled() && (fileIterator != end || futures.size() != 0)) { if (futures.size() >= MAX_THREADS || fileIterator == end) { // We don't want to start a new thread (yet), so try to find a future that is ready and // handle its result. reduceOne(futureInterface, futures, state, reduce); } else { // start a new thread futures.push_back(std::async(std::launch::async, map, futureInterface, *fileIterator)); ++fileIterator; } } } template void blockingMapReduce(QFutureInterface futureInterface, const Container &container, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto state = init(futureInterface); mapReduceLoop(futureInterface, container, map, state, reduce); cleanup(futureInterface, state); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } template typename std::enable_if::type>::value>::type runAsyncImpl(QFutureInterface futureInterface, Function &&function, Obj &&obj, Args&&... args) { std::mem_fn(std::forward(function))(std::forward(obj), futureInterface, std::forward(args)...); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } template typename std::enable_if::type>::value>::type runAsyncImpl(QFutureInterface futureInterface, Function &&function, Args&&... args) { function(futureInterface, std::forward(args)...); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } // can be replaced with std::(make_)index_sequence with C++14 template struct indexSequence { }; template struct makeIndexSequence : makeIndexSequence { }; template struct makeIndexSequence<0, S...> { typedef indexSequence type; }; template typename std::decay::type decayCopy(T&& v) { return std::forward(v); } template class AsyncJob : public QRunnable { public: AsyncJob(Function &&function, Args&&... args) // decay copy like std::thread : data(decayCopy(std::forward(function)), decayCopy(std::forward(args))...) { // we need to report it as started even though it isn't yet, because someone might // call waitForFinished on the future, which does _not_ block if the future is not started futureInterface.setRunnable(this); futureInterface.reportStarted(); } ~AsyncJob() { // QThreadPool can delete runnables even if they were never run (e.g. QThreadPool::clear). // Since we reported them as started, we make sure that we always report them as finished. // reportFinished only actually sends the signal if it wasn't already finished. futureInterface.reportFinished(); } QFuture future() { return futureInterface.future(); } void run() override { if (priority != QThread::InheritPriority) if (QThread *thread = QThread::currentThread()) if (thread != qApp->thread()) thread->setPriority(priority); if (futureInterface.isCanceled()) { futureInterface.reportFinished(); return; } runHelper(typename makeIndexSequence::value>::type()); } void setThreadPool(QThreadPool *pool) { futureInterface.setThreadPool(pool); } void setThreadPriority(QThread::Priority p) { priority = p; } private: using Data = std::tuple::type, typename std::decay::type...>; template void runHelper(indexSequence) { // invalidates data, which is moved into the call runAsyncImpl(futureInterface, std::move(std::get(data))...); } Data data; QFutureInterface futureInterface; QThread::Priority priority = QThread::InheritPriority; }; class QTCREATOR_UTILS_EXPORT RunnableThread : public QThread { public: explicit RunnableThread(QRunnable *runnable, QObject *parent = 0); protected: void run(); private: QRunnable *m_runnable; }; } // Internal template QFuture mapReduce(std::reference_wrapper containerWrapper, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto fi = QFutureInterface(); QFuture future = fi.future(); fi.reportStarted(); std::thread(Internal::blockingMapReduce, fi, containerWrapper, init, map, reduce, cleanup).detach(); return future; } template QFuture mapReduce(const Container &container, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto fi = QFutureInterface(); QFuture future = fi.future(); std::thread(Internal::blockingMapReduce, fi, container, init, map, reduce, cleanup).detach(); return future; } /*! The interface of \c {runAsync} is similar to the std::thread constructor and \c {std::invoke}. The \a function argument can be a member function, an object with \c {operator()}, a \c {std::function}, lambda, function pointer or function reference. They need to take a \c {QFutureInterface&} as their first argument, followed by other custom arguments which need to be passed to this function. If \a function is a (non-static) member function, the first argument in \a args is expected to be the object that the function is called on. \sa std::thread \sa std::invoke */ template QFuture runAsync(QThread::Priority priority, Function &&function, Args&&... args) { auto job = new Internal::AsyncJob (std::forward(function), std::forward(args)...); job->setThreadPriority(priority); QFuture future = job->future(); auto thread = new Internal::RunnableThread(job); thread->moveToThread(qApp->thread()); // make sure thread gets deleteLater on main thread QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); thread->start(); return future; } template ::type, QThreadPool>::value && !std::is_same::type, QThread::Priority>::value >::type> QFuture runAsync(Function &&function, Args&&... args) { return runAsync(QThread::InheritPriority, std::forward(function), std::forward(args)...); } template QFuture runAsync(QThreadPool *pool, QThread::Priority priority, Function &&function, Args&&... args) { auto job = new Internal::AsyncJob (std::forward(function), std::forward(args)...); job->setThreadPool(pool); job->setThreadPriority(priority); QFuture future = job->future(); pool->start(job); return future; } template ::type, QThread::Priority>::value >::type> QFuture runAsync(QThreadPool *pool, Function &&function, Args&&... args) { return runAsync(pool, QThread::InheritPriority, std::forward(function), std::forward(args)...); } } // Utils #endif // RUNEXTENSIONS_H