Qt编程:Qt / C ++多线程Tasks

【链接】:tasks:https://github.com/mhogomchungu/tasks

    Qt / C ++中使用任务和延续进行异步编程。项目旨在使用现代C ++在Qt / C ++中进行基于异步的编程

#ifndef __TASK_H_INCLUDED__
#define __TASK_H_INCLUDED__

#include <type_traits>
#include <vector>
#include <utility>
#include <future>
#include <functional>
#include <QThread>
#include <QEventLoop>
#include <QMutex>
#include <QProcess>
#include <QVariant>

namespace Task
{
	template< typename T >
	class future;

	namespace detail
	{
		template< typename T >
		void add_void(Task::future< T >&, Task::future< T >&, std::function< T() >&&);
		template< typename T >
		void add(Task::future< T >&, Task::future< T >&, std::function< void(T) >&&);

		template<typename Function>
		class functionWrapper
		{
		public:
			template< typename ... Args >
			auto operator()(Args&& ... args) const
			{
				return (*m_function)(std::forward<Args>(args) ...);
			}
			functionWrapper(Function function) :
				m_function(std::make_shared<Function>(Function(std::move(function))))
			{
			}
		private:
			std::shared_ptr<Function> m_function;
		};

		template<typename Function>
		functionWrapper<Function> function(Function function)
		{
			return functionWrapper<Function>(std::move(function));
		}

#if __cplusplus >= 201703L
		template<typename Function, typename ... Args>
		using result_of = std::invoke_result_t<Function, Args ...>;
#else
		template<typename Function, typename ... Args>
		using result_of = std::result_of_t<Function(Args ...)>;
#endif
		template<typename Function>
		using copyable = std::enable_if_t<std::is_copy_constructible<Function>::value, int>;

		template<typename Function>
		using not_copyable = std::enable_if_t<!std::is_copy_constructible<Function>::value, int>;

		template<typename ReturnType, typename Function, typename ... Args>
		using has_same_return_type = std::enable_if_t<std::is_same<result_of<Function, Args...>, ReturnType>::value, int>;

		template<typename Function, typename ... Args>
		using has_void_return_type = has_same_return_type<void, Function, Args...>;

		template<typename Function, typename ... Args>
		using has_bool_return_type = has_same_return_type<bool, Function, Args...>;

		template<typename Function, typename ... Args>
		using has_non_void_return_type = std::enable_if_t<!std::is_void<result_of<Function, Args...>>::value, int>;

		template<typename Function, typename ... Args>
		using has_argument = has_same_return_type<result_of<Function, Args...>, Function, Args...>;

		template<typename Function>
		using has_no_argument = has_same_return_type<result_of<Function>, Function>;

		template<typename Function, typename ... Args>
		using returns_void = has_void_return_type<Function, Args...>;

		template<typename Function, typename ... Args>
		using returns_value = has_non_void_return_type<Function, Args...>;
	}

	template< typename T >
	struct pair {
		pair(std::function< T() > first, std::function< void(T) > second) :
			value(std::make_pair(std::move(first), std::move(second)))
		{
		}
		std::pair< std::function< T() >, std::function< void(T) > > value;
	};

	template<>
	struct pair<void> {
		pair(std::function< void() > first, std::function< void() > second) :
			value(std::make_pair(std::move(first), std::move(second)))
		{
		}
		std::pair< std::function< void() >, std::function< void() > > value;
	};
	template< typename E,
		typename F,
		Task::detail::not_copyable<E> = 0,
		Task::detail::not_copyable<F> = 0 >
		pair<Task::detail::result_of<E>> make_pair(E e, F f)
	{
		using type = Task::detail::result_of<E>;
		return pair<type>(Task::detail::function(std::move(e)), Task::detail::function(std::move(f)));
	}
	template< typename E,
		typename F,
		Task::detail::copyable<E> = 0,
		Task::detail::copyable<F> = 0 >
		pair<Task::detail::result_of<E>> make_pair(E e, F f)
	{
		return pair<Task::detail::result_of<E>>(std::move(e), std::move(f));
	}
	template< typename E,
		typename F,
		Task::detail::not_copyable<E> = 0,
		Task::detail::copyable<F> = 0 >
		pair<Task::detail::result_of<E>> make_pair(E e, F f)
	{
		using type = Task::detail::result_of<E>;
		return pair<type>(Task::detail::function(std::move(e)), std::move(f));
	}
	template< typename E,
		typename F,
		Task::detail::copyable<E> = 0,
		Task::detail::not_copyable<F> = 0 >
		pair<Task::detail::result_of<E>> make_pair(E e, F f)
	{
		using type = Task::detail::result_of<E>;
		return pair<type>(std::move(e), Task::detail::function(std::move(f)));
	}
	template< typename T >
	class future : private QObject
	{
	public:
		/*
		 * Use this API if you care about the result
		 */
		 //std::function< void( T ) >
		template<typename Function,
			Task::detail::has_argument<Function, T> = 0,
			Task::detail::copyable<Function> = 0>
			void then(Function function)
		{
			m_function = std::move(function);
			this->start();
		}
		template<typename Function,
			Task::detail::has_argument<Function, T> = 0,
			Task::detail::not_copyable<Function> = 0>
			void then(Function function)
		{
			m_function = Task::detail::function(std::move(function));
			this->start();
		}
		/*
		 * Use this API if you DO NOT care about the result
		 */
		 //std::function< void( void ) >
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::copyable<Function> = 0>
			void then(Function function)
		{
			m_function_1 = std::move(function);
			this->start();
		}
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::not_copyable<Function> = 0>
			void then(Function function)
		{
			m_function_1 = Task::detail::function(std::move(function));
			this->start();
		}
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::not_copyable<Function> = 0>
			void queue(Function function)
		{
			if (this->manages_multiple_futures()) {

				m_function_1 = Task::detail::function(std::move(function));

				this->_queue();
			}
			else {
				this->then(Task::detail::function(std::move(function)));
			}
		}
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::copyable<Function> = 0>
			void queue(Function function)
		{
			if (this->manages_multiple_futures()) {

				m_function_1 = std::move(function);

				this->_queue();
			}
			else {
				this->then(std::move(function));
			}
		}

		void queue()
		{
			if (this->manages_multiple_futures()) {

				m_function_1 = []() {};

				this->_queue();
			}
			else {
				this->then([]() {});
			}
		}
		/*
		 * Below two API just exposes existing functionality using more standard names
		 */
		template<typename Function>
		void when_all(Function function)
		{
			this->then(std::move(function));
		}
		template<typename Function>
		void when_seq(Function function)
		{
			this->queue(std::move(function));
		}
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::copyable<Function> = 0>
			void when_any(Function function)
		{
			if (this->manages_multiple_futures()) {

				this->_when_any(std::move(function));
			}
			else {
				this->then(std::move(function));
			}
		}
		template<typename Function,
			Task::detail::has_no_argument<Function> = 0,
			Task::detail::not_copyable<Function> = 0>
			void when_any(Function function)
		{
			if (this->manages_multiple_futures()) {

				this->_when_any(Task::detail::function(std::move(function)));
			}
			else {
				this->then(Task::detail::function(std::move(function)));
			}
		}
		void when_all()
		{
			this->then([]() {});
		}
		void when_seq()
		{
			this->queue([]() {});
		}
		void when_any()
		{
			if (this->manages_multiple_futures()) {

				this->_when_any([]() {});
			}
			else {
				this->then([]() {});
			}
		}
		T get()
		{
			if (this->manages_multiple_futures()) {

				for (auto& it : m_tasks) {

					it.second(it.first->get());
				}

				this->deleteLater();

				return T();
			}
			else {
				return m_get();
			}
		}
		T await()
		{
			QEventLoop p;

			T q;

			m_function = [&](T&& r) { q = std::move(r); p.exit(); };

			this->start();

			p.exec();

			return q;
		}
		bool manages_multiple_futures()
		{
			return m_tasks.size() > 0;
		}
		const std::vector< QThread * >& all_threads()
		{
			return m_threads;
		}
		QThread * first_thread()
		{
			return m_threads[0];
		}
		QThread * thread_at(std::vector< QThread * >::size_type s)
		{
			return m_threads[s];
		}
		void start()
		{
			if (this->manages_multiple_futures()) {

				this->_start();
			}
			else {
				m_start();
			}
		}
		void cancel()
		{
			if (this->manages_multiple_futures()) {

				for (auto& it : m_tasks) {

					it.first->cancel();
				}

				this->deleteLater();
			}
			else {
				m_cancel();
			}
		}
		future() = default;
		future(const future&) = delete;
		future(future&&) = delete;
		future& operator=(const future&) = delete;
		future& operator=(future&&) = delete;

		future(QThread * e,
			std::function< void() >&& start,
			std::function< void() >&& cancel,
			std::function< T() >&& get) :
			m_thread(e),
			m_start(std::move(start)),
			m_cancel(std::move(cancel)),
			m_get(std::move(get))
		{
			if (m_thread) {

				m_threads.push_back(m_thread);
			}
			else {
				/*
				 * This object was created by "_private_future< T >()" class.
				 * It has no QThread of its own because it only manages other futures.
				 *
				 */
			}
		}
		void run(T&& r)
		{
			if (m_function_1 != nullptr) {

				m_function_1();

			}
			else if (m_function != nullptr) {

				m_function(std::move(r));
			}
		}

		template< typename E >
		friend void Task::detail::add(Task::future< E >&,
			Task::future< E >&,
			std::function< void(E) >&&);
	private:
		void _when_any(std::function< void() > function)
		{
			m_when_any_function = std::move(function);

			for (auto& it : m_tasks) {

				it.first->then([&](T&& e) {

					QMutexLocker m(&m_mutex);

					m_counter++;

					if (m_task_not_run) {

						m_task_not_run = false;

						m.unlock();

						it.second(std::forward<T>(e));

						m_when_any_function();
					}
					else {
						m.unlock();
						it.second(std::forward<T>(e));
					}

					if (m_counter == m_tasks.size()) {

						this->deleteLater();
					}
				});
			}
		}
		void _queue()
		{
			m_tasks[m_counter].first->then([this](T&& e) {

				m_tasks[m_counter].second(std::forward<T>(e));

				m_counter++;

				if (m_counter == m_tasks.size()) {

					m_function_1();

					this->deleteLater();
				}
				else {
					this->_queue();
				}
			});
		}
		void _start()
		{
			for (auto& it : m_tasks) {

				it.first->then([&](T&& e) {

					QMutexLocker m(&m_mutex);

					Q_UNUSED(m);

					m_counter++;

					it.second(std::forward<T>(e));

					if (m_counter == m_tasks.size()) {

						if (m_function_1 != nullptr) {

							m_function_1();

						}
						else if (m_function != nullptr) {

							m_function(T());
						}

						this->deleteLater();
					}
				});
			}
		}

		QThread * m_thread = nullptr;
		std::function< void(T) > m_function = nullptr;
		std::function< void() > m_function_1 = nullptr;
		std::function< void() > m_start = []() {};
		std::function< void() > m_cancel = []() {};
		std::function< T() > m_get = []() { return T(); };
		std::function< void() > m_when_any_function;

		QMutex m_mutex;
		std::vector< std::pair< Task::future< T > *, std::function< void(T) > > > m_tasks;
		std::vector< QThread * > m_threads;
		decltype(m_tasks.size()) m_counter = 0;
		bool m_task_not_run = true;
	};

	template<>
	class future< void > : private QObject
	{
	public:
		template<typename Function, Task::detail::copyable<Function> = 0>
		void then(Function function)
		{
			m_function = std::move(function);
			this->start();
		}
		template<typename Function, Task::detail::not_copyable<Function> = 0>
		void then(Function function)
		{
			m_function = Task::detail::function(std::move(function));
			this->start();
		}
		template<typename Function, Task::detail::copyable<Function> = 0>
		void queue(Function function)
		{
			if (this->manages_multiple_futures()) {

				m_function = std::move(function);

				this->_queue();
			}
			else {
				this->then(std::move(function));
			}
		}
		template<typename Function, Task::detail::not_copyable<Function> = 0>
		void queue(Function function)
		{
			if (this->manages_multiple_futures()) {

				m_function = Task::detail::function(std::move(function));

				this->_queue();
			}
			else {
				this->then(Task::detail::function(std::move(function)));
			}
		}
		void queue()
		{
			if (this->manages_multiple_futures()) {

				m_function = []() {};

				this->_queue();
			}
			else {
				this->then([]() {});
			}
		}
		void when_any()
		{
			if (this->manages_multiple_futures()) {

				this->_when_any([]() {});
			}
			else {
				this->then([]() {});
			}
		}
		template<typename Function, Task::detail::copyable<Function> = 0>
		void when_any(Function function)
		{
			if (this->manages_multiple_futures()) {

				this->_when_any(std::move(function));
			}
			else {
				this->then(std::move(function));
			}
		}
		template<typename Function, Task::detail::not_copyable<Function> = 0>
		void when_any(Function function)
		{
			if (this->manages_multiple_futures()) {

				this->_when_any(Task::detail::function(std::move(function)));
			}
			else {
				this->then(Task::detail::function(std::move(function)));
			}
		}
		/*
		 * Below two API just exposes existing functionality using more standard names
		 */
		template<typename Function>
		void when_all(Function function)
		{
			this->then(std::move(function));
		}
		template<typename Function>
		void when_seq(Function function)
		{
			this->queue(std::move(function));
		}
		void when_all()
		{
			this->then([]() {});
		}
		void when_seq()
		{
			this->queue();
		}
		void get()
		{
			if (this->manages_multiple_futures()) {

				for (auto& it : m_tasks) {

					it.first->get();
					it.second();
				}

				this->deleteLater();
			}
			else {
				m_get();
			}
		}
		void await()
		{
			QEventLoop p;

			m_function = [&]() { p.exit(); };

			this->start();

			p.exec();
		}
		bool manages_multiple_futures()
		{
			return m_tasks.size() > 0;
		}
		const std::vector< QThread * >& all_threads()
		{
			return m_threads;
		}
		QThread * first_thread()
		{
			return m_threads[0];
		}
		QThread * thread_at(std::vector< QThread * >::size_type s)
		{
			return m_threads[s];
		}
		void start()
		{
			if (this->manages_multiple_futures()) {

				this->_start();
			}
			else {
				m_start();
			}
		}
		void cancel()
		{
			if (this->manages_multiple_futures()) {

				for (auto& it : m_tasks) {

					it.first->cancel();
				}

				this->deleteLater();
			}
			else {
				m_cancel();
			}
		}
		future() = default;
		future(const future&) = delete;
		future(future&&) = delete;
		future& operator=(const future&) = delete;
		future& operator=(future&&) = delete;

		future(QThread * e,
			std::function< void() >&& start,
			std::function< void() >&& cancel,
			std::function< void() >&& get) :
			m_thread(e),
			m_start(std::move(start)),
			m_cancel(std::move(cancel)),
			m_get(std::move(get))
		{
			if (m_thread) {

				m_threads.push_back(m_thread);
			}
			else {
				/*
				 * This object was created by "_private_future< T >()" class.
				 * It has no QThread of its own because it only manages other futures.
				 *
				 */
			}
		}

		template< typename T >
		friend void Task::detail::add_void(Task::future< T >&,
			Task::future< T >&,
			std::function< T() >&&);
		void run()
		{
			m_function();
		}
	private:
		void _when_any(std::function< void() > function)
		{
			m_when_any_function = std::move(function);

			for (auto& it : m_tasks) {

				it.first->then([&]() {

					QMutexLocker m(&m_mutex);

					m_counter++;

					if (m_task_not_run) {

						m_task_not_run = false;

						m.unlock();

						it.second();

						m_when_any_function();
					}
					else {
						m.unlock();
						it.second();
					}

					if (m_counter == m_tasks.size()) {

						this->deleteLater();
					}
				});
			}
		}
		void _queue()
		{
			m_tasks[m_counter].first->then([this]() {

				m_tasks[m_counter].second();

				m_counter++;

				if (m_counter == m_tasks.size()) {

					m_function();

					this->deleteLater();
				}
				else {
					this->_queue();
				}
			});
		}

		void _start()
		{
			for (auto& it : m_tasks) {

				it.first->then([&]() {

					QMutexLocker m(&m_mutex);

					Q_UNUSED(m);

					m_counter++;

					it.second();

					if (m_counter == m_tasks.size()) {

						m_function();

						this->deleteLater();
					}
				});
			}
		}

		QThread * m_thread = nullptr;

		std::function< void() > m_function = []() {};
		std::function< void() > m_start = []() {};
		std::function< void() > m_cancel = []() {};
		std::function< void() > m_get = []() {};
		std::function< void() > m_when_any_function;
		QMutex m_mutex;
		std::vector< std::pair< Task::future< void > *, std::function< void() > > > m_tasks;
		std::vector< QThread * > m_threads;
		decltype(m_tasks.size()) m_counter = 0;
		bool m_task_not_run = true;
	};

	namespace detail
	{
		/*
		 * -------------------------Start of internal helper functions-------------------------
		 */
		template< typename Type, typename Function >
		class ThreadHelper : public QThread
		{
		public:
			ThreadHelper(Function function) :
				m_function(std::move(function)),
				m_future(this,
					[this]() { this->start(); },
					[this]() { this->deleteLater(); },
					[this]() { this->deleteLater(); return m_function(); })
			{
				connect(this, &QThread::finished, this, &QThread::deleteLater);
			}
			Task::future<Type>& Future()
			{
				return m_future;
			}
		private:
			~ThreadHelper()
			{
				m_future.run(std::move(m_result));
			}
			void run()
			{
				m_result = m_function();
			}
			Function m_function;
			Task::future<Type> m_future;
			Type m_result;
		};

		template< typename Function>
		class ThreadHelperVoid : public QThread
		{
		public:
			ThreadHelperVoid(Function function) :
				m_function(std::move(function)),
				m_future(this,
					[this]() { this->start(); },
					[this]() { this->deleteLater(); },
					[this]() { m_function(); this->deleteLater(); })
			{
				connect(this, &QThread::finished, this, &QThread::deleteLater);
			}
			Task::future< void >& Future()
			{
				return m_future;
			}
		private:
			~ThreadHelperVoid()
			{
				m_future.run();
			}
			void run()
			{
				m_function();
			}
			Function m_function;
			Task::future< void > m_future;
		};
		template<typename Fn, Task::detail::returns_value<Fn> = 0>
		Task::future<Task::detail::result_of<Fn>>& run(Fn function)
		{
			using t = Task::detail::result_of<Fn>;

			return (new ThreadHelper<t, Fn>(std::move(function)))->Future();
		}
		template<typename Fn, Task::detail::returns_void<Fn> = 0>
		Task::future<Task::detail::result_of<Fn>>& run(Fn function)
		{
			return (new ThreadHelperVoid<Fn>(std::move(function)))->Future();
		}
		template< typename T >
		void add(Task::future< T >& a, Task::future< T >& b, std::function< void(T) >&& c)
		{
			a.m_tasks.emplace_back(std::addressof(b), std::move(c));
			a.m_threads.push_back(b.m_thread);
		}

		template< typename T >
		void add_void(Task::future< T >& a, Task::future< T >& b, std::function< T() >&& c)
		{
			a.m_tasks.emplace_back(std::addressof(b), std::move(c));
			a.m_threads.push_back(b.m_thread);
		}

		template< typename T >
		void add_task(Task::future< T >& f)
		{
			Q_UNUSED(f)
		}

		template< typename T >
		void add_future(Task::future< T >& f)
		{
			Q_UNUSED(f)
		}

		template< typename T >
		void add_pair(Task::future< T >& f)
		{
			Q_UNUSED(f)
		}

		template< typename T >
		void add_pair_void(Task::future< T >& f)
		{
			Q_UNUSED(f)
		}

		template< typename ... T,
			typename Function,
			Task::detail::not_copyable<Function> = 0 >
			void add_task(Task::future< void >& f, Function e, T&& ... t);

		template< typename ... T,
			typename Function,
			Task::detail::copyable<Function> = 0 >
			void add_task(Task::future< void >& f, Function e, T&& ... t)
		{
			add_void(f, Task::detail::run(std::function< void() >(std::move(e))),
				std::function< void() >([]() {}));
			add_task(f, std::forward<T>(t) ...);
		}

		template< typename ... T,
			typename Function,
			Task::detail::not_copyable<Function> >
			void add_task(Task::future< void >& f, Function e, T&& ... t)
		{
			auto a = std::function< void() >(Task::detail::function(std::move(e)));

			add_void(f, Task::detail::run(std::move(a)),
				std::function< void() >([]() {}));

			add_task(f, std::forward<T>(t) ...);
		}

		template< typename ... T >
		void add_future(Task::future< void >& f, Task::future< void >& e, T&& ... t)
		{
			add_void(f, e, std::function< void() >([]() {}));
			add_future(f, std::forward<T>(t) ...);
		}

		template< typename E, typename F, typename ... T >
		void add_pair(Task::future< E >& f, F&& s, T&& ... t)
		{
			add(f, Task::detail::run(std::move(s.value.first)), std::move(s.value.second));
			add_pair(f, std::forward<T>(t) ...);
		}

		template< typename F, typename ... T >
		void add_pair_void(Task::future< void >& f, F&& s, T&& ... t)
		{
			add_void(f, Task::detail::run(std::move(s.value.first)), std::move(s.value.second));
			add_pair_void(f, std::forward<T>(t) ...);
		}

		template< typename T >
		Task::future< T >& future()
		{
			return *(new Task::future< T >());
		}

	} //end of detail namespace


	/*
	 * -------------------------End of internal helper functions-------------------------
	 */
	template< typename Fn, Task::detail::copyable<Fn> = 0 >
	auto& run(Fn function)
	{
		return Task::detail::run(std::move(function));
	}
	template< typename Fn, Task::detail::not_copyable<Fn> = 0 >
	auto& run(Fn function)
	{
		return Task::detail::run(Task::detail::function(std::move(function)));
	}
#if __cplusplus > 201703L
	template< typename Fn, typename ... Args >
	future<std::invoke_result_t<Fn, Args...>>& run(Fn function, Args ... args)
	{
		return Task::run([function = std::move(function), ... args = std::move(args)]()mutable{

			return function(std::move(args) ...);
		});
	}
#elif __cplusplus == 201703L
	template< typename Fn, typename ... Args >
	future<std::invoke_result_t<Fn, Args...>>& run(Fn function, Args ... args)
	{
		return Task::run([args = std::make_tuple(std::move(args) ...), function = std::move(function)]()mutable{

			return std::apply([function = std::move(function)](Args ... args){

				return function(std::move(args) ...);

			}, std::move(args));
		});
	}
#else
	template< typename Fn, typename ... Args >
	future<std::result_of_t<Fn(Args...)>>& run(Fn function, Args ... args)
	{
		return Task::run([=, function = std::move(function)](){

			return function(std::move(args) ...);
		});
	}
#endif
	class progress : public QObject {
		Q_OBJECT
	public:
		template< typename function >
		progress(QObject * obj, function fn)
		{
			connect(this, &progress::update, obj, std::move(fn));
		}
	signals:
		void update(QVariant x) const;
	private:
	};

	template< typename Fn, typename cb >
	future<Task::detail::result_of<Fn, const progress&>>& run(QObject * obj, Fn function, cb rp)
	{
		return Task::run([obj, rp = std::move(rp), function = std::move(function)](){

			return function(progress(obj, std::move(rp)));
		});
	}

	template< typename Function,
		Task::detail::copyable<Function> = 0,
		typename ... T >
		Task::future< void >& run_tasks(Function f, T ... t)
	{
		auto& e = Task::detail::future< void >();
		Task::detail::add_task(e, std::move(f), std::move(t) ...);
		return e;
	}
	template< typename Function,
		Task::detail::not_copyable<Function> = 0,
		typename ... T >
		Task::future< void >& run_tasks(Function f, T ... t)
	{
		auto& e = Task::detail::future< void >();
		Task::detail::add_task(e, Task::detail::function(std::move(f)), std::move(t) ...);
		return e;
	}

	template< typename ... T >
	Task::future< void >& run_tasks(Task::future< void >& s, T&& ... t)
	{
		auto& e = Task::detail::future< void >();
		Task::detail::add_future(e, s, std::forward<T>(t) ...);
		return e;
	}

	template< typename ... T >
	Task::future< void >& run(pair< void > s, T ... t)
	{
		auto& e = Task::detail::future< void >();
		Task::detail::add_pair_void(e, std::move(s), std::move(t) ...);
		return e;
	}

	template< typename E, typename ... T >
	Task::future< E >& run(pair< E > s, T ... t)
	{
		auto& e = Task::detail::future< E >();
		Task::detail::add_pair(e, std::move(s), std::move(t) ...);
		return e;
	}

	/*
	 *
	 * A few useful helper functions
	 *
	 */
	template< typename Fn >
	Task::detail::result_of<Fn> await(Fn function)
	{
		return Task::run(std::move(function)).await();
	}

	template< typename Fn, typename ... Args >
	Task::detail::result_of<Fn, Args ...> await(Fn function, Args ... args)
	{
		return Task::run(std::move(function), std::move(args) ...).await();
	}
	template< typename T >
	T await(Task::future<T>& e)
	{
		return e.await();
	}

	template< typename T >
	T await(std::future<T> t)
	{
		return Task::await<T>([&]() { return t.get(); });
	}

	/*
	 * These methods run their arguments in a separate thread and does not offer
	 * continuation feature.Useful when wanting to just run a function in a
	 * different thread.
	 */
	template< typename Fn >
	void exec(Fn function)
	{
		Task::run(std::move(function)).start();
	}
	template< typename Fn, typename ... Args >
	void exec(Fn function, Args ... args)
	{
		Task::run(std::move(function), std::move(args) ...).start();
	}
	template< typename T >
	void exec(Task::future<T>& e)
	{
		e.start();
	}

	namespace process {

		class result {
		public:
			result() = default;
			result(int exit_code) :
				m_finished(true),
				m_exitCode(exit_code),
				m_exitStatus(0)
			{
			}
			template< typename E, typename F >
			result(E&& std_out,
				F&& std_error,
				int exit_code,
				int exit_status,
				bool finished) :
				m_stdOut(std::forward<E>(std_out)),
				m_stdError(std::forward<F>(std_error)),
				m_finished(finished),
				m_exitCode(exit_code),
				m_exitStatus(exit_status)
			{
			}
			result(QProcess& e, int s)
			{
				m_finished = e.waitForFinished(s);
				m_stdOut = e.readAllStandardOutput();
				m_stdError = e.readAllStandardError();
				m_exitCode = e.exitCode();
				m_exitStatus = e.exitStatus();
			}
			const QByteArray& std_out() const
			{
				return m_stdOut;
			}
			const QByteArray& std_error() const
			{
				return m_stdError;
			}
			bool finished() const
			{
				return m_finished;
			}
			bool success() const
			{
				return m_exitCode == 0 &&
					m_exitStatus == QProcess::NormalExit &&
					m_finished == true;
			}
			bool failed() const
			{
				return !this->success();
			}
			int exit_code() const
			{
				return m_exitCode;
			}
			int exit_status() const
			{
				return m_exitStatus;
			}
		private:
			QByteArray m_stdOut;
			QByteArray m_stdError;
			bool m_finished = false;
			int m_exitCode = 255;
			int m_exitStatus = 255;
		};

		static inline Task::future< result >& run(const QString& cmd,
			const QStringList& args,
			int waitTime = -1,
			const QByteArray& password = QByteArray(),
			const QProcessEnvironment& env = QProcessEnvironment(),
			std::function< void() > setUp_child_process = []() {})
		{
			return Task::run([=]() {

				class Process : public QProcess {
				public:
					Process(std::function< void() > function,
						const QProcessEnvironment& env) :
						m_function(std::move(function))
					{
						this->setProcessEnvironment(env);
					}
				protected:
					void setupChildProcess()
					{
						m_function();
					}
				private:
					std::function< void() > m_function;

				} exe(std::move(setUp_child_process), env);

				if (args.isEmpty()) {

#if QT_VERSION < QT_VERSION_CHECK( 5,15,0 )
					exe.start(cmd);
#else
					exe.start(cmd, args);
#endif
				}
				else {
					exe.start(cmd, args);
				}

				if (!password.isEmpty()) {

					exe.waitForStarted(waitTime);
					exe.write(password);
					exe.closeWriteChannel();
				}

				return result(exe, waitTime);
			});
		}

		static inline Task::future< result >& run(const QString& cmd, const QByteArray& password)
		{
			return Task::process::run(cmd, {}, -1, password);
		}

		static inline Task::future< result >& run(const QString& cmd,
			const QStringList& args,
			const QByteArray& password)
		{
			return Task::process::run(cmd, args, -1, password);
		}
	}
}

这是一个基于Qt的异步任务处理库,提供了类似C++标准库std::future的功能,但更加灵活且与Qt框架深度集成。

核心设计

1.1 主要特性

  • 支持异步任务执行

  • 提供多种任务执行模式:并行、串行、任意完成等

  • 与Qt事件循环集成,支持GUI线程不阻塞

  • 支持任务链式调用

  • 提供进程执行封装

1.2 核心类

  • Task::future<T>: 模板类,表示异步操作的结果

  • Task::pair<T>: 辅助结构,用于组合任务函数和回调函数

  • Task::progress: 进度报告类

  • Task::process::result: 进程执行结果类

2. 关键实现细节

2.1 future类实现

future<T>是核心类,有两种特化版本:

  1. future<T>: 处理有返回值的任务

  2. future<void>: 处理无返回值的任务

主要方法:
  • then(): 添加完成回调

  • await(): 同步等待结果(不阻塞GUI)

  • get(): 同步获取结果(可能阻塞)

  • queue(): 串行执行任务

  • when_all()/when_any(): 并行执行控制

  • start(): 启动任务

  • cancel(): 取消任务

内部机制:
  • 使用QThread在后台执行任务

  • 通过QEventLoop实现非阻塞等待

  • 使用QMutex进行线程同步

2.2 任务执行流程

  1. 用户通过Task::run()创建任务

  2. 库内部创建ThreadHelperThreadHelperVoid(继承自QThread)

  3. 线程完成后通过Qt信号槽机制通知主线程

  4. 主线程执行回调函数

2.3 模板元编程技巧

库中大量使用了SFINAE和模板元编程来实现函数签名的检查和适配:

template<typename Function>
using copyable = std::enable_if_t<std::is_copy_constructible<Function>::value, int>;

template<typename Function>
using not_copyable = std::enable_if_t<!std::is_copy_constructible<Function>::value, int>;

这些特性用于:

  • 区分可复制和不可复制的函数对象

  • 检查函数返回类型

  • 适配不同参数数量的函数

3. 使用示例

根据接口设计,典型用法可能如下:

3.1 基本用法

// 异步执行并获取结果
auto& task = Task::run([]{
    return someHeavyComputation(); 
});
task.then([](auto result){
    // 在主线程处理结果
    updateUI(result);
});

3.2 串行任务

auto& tasks = Task::run_tasks(
    []{ return task1(); },
    []{ return task2(); },
    []{ return task3(); }
);
tasks.queue([]{
    // 所有任务完成后执行
});

3.3 进程执行

auto& proc = Task::process::run("git", {"pull"});
proc.then([](const Task::process::result& r){
    if(r.success()) {
        qDebug() << "Git pull succeeded";
    }
});

功能测试

#include "task.hpp"
#include "example.h"

#include <QString>
#include <QMetaObject>
#include <QCoreApplication>
#include <iostream>

static void _testing_task_await();
static void _testing_task_future_all();
static void _testing_multiple_tasks();
static void _testing_multiple_tasks_with_start();
static void _testing_queue_with_no_results();
static void _testing_queue_with_results();
static void _testing_checking_multiple_futures();

template< typename T >
static void _print(const T& e)
{
	std::cout << e << std::endl;
}

struct wait {

	void task_finished(const char * s)
	{
		QMutexLocker m(&mutex);

		counter++;

		std::cout << s << std::endl;

		if (counter == max) {

			loop.exit();
		}
	}
	int max = 3;
	int counter = 0;
	QMutex mutex;
	QEventLoop loop;
};

void example::start()
{
	QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection);
}

QString _longRunningTask()
{
	return "abc";
}

static void _printThreadID()
{
	std::cout << "Thread id: " << QThread::currentThreadId() << std::endl;
}

static void _useResult(const QString& e)
{
	Q_UNUSED(e)
}

/*
 * A sample use where a task is run on separate thread and return a value and the returned
 * value is used on another task run on the original thread
 */
static void _test_run_then()
{
	std::cout << "Testing Task::run().then()" << std::endl;

	/*
	 * print the thread id to know we are on what thread.
	 * We are on the original thread here.
	 */
	_printThreadID();

	Task::run([]() {

		/*
		 * print the thread id to know we are on what thread.
		 * We are on a separate thread here
		 */
		_printThreadID();

		/*
		 * Do a time consuming process on a separate thread and return its result
		 */
		return _longRunningTask();

	}).then([](QString r) {

		/*
		 * use the returned value by the previous task
		 */
		_useResult(r);
		/*
		 * print the thread id to know we are on what thread.
		 * We are back on the original thread and we will get here as a continuation of the task
		 * that completed above
		 */
		_printThreadID();

		/*
		 * moving on to the next test.
		 */
		_testing_task_await();
	});
}

/*
 * Task::await() function below does the following:
 * 1. suspends the "_testing_task_await" method at a point where Task::await() method is called.
 * 2. creates a new thread.
 * 3. runs the _longRunningTask method in the new thread.
 * 4. store the result of  _longRunningTask function in r.
 * 5. resumes "_testing_task_await" method.
 */
static void _testing_task_await()
{
	_print("Testing Task::await()");

	QString e = Task::await(_longRunningTask);

	_print(e.toLatin1().constData());

	/*
	 * moving on to the next test.
	 */
	_testing_task_future_all();
}

/*
 * Task::run() function below does the following:
 * 1. Collects a bunch of tasks.
 * 2. Runs each task on its own thread.
 * 3. Returns a future that holds all above tasks.
 * 4. .await() can be called on the future to suspend the current thread at a point
 *    where this medhod is called to wait for all tasks to finish.
 * 5. .then() can be called on the future to register an event to be called when all
 *    tasks finish running.
 */
static void _testing_task_future_all()
{
	auto fn1 = []() { _printThreadID(); };
	auto fn2 = []() { _printThreadID(); };
	auto fn3 = []() { _printThreadID(); };

	_print("Testing Task::run().await() multiple tasks");

	Task::future<void>& e = Task::run_tasks(fn1, fn2, fn3);

	e.await();

	_print("Testing Task::run().then() multiple tasks");

	Task::future<void>& f1 = Task::run(fn1);
	Task::future<void>& f2 = Task::run(fn2);
	Task::future<void>& f3 = Task::run(fn3);

	Task::future<void>& s = Task::run_tasks(f1, f2, f3);

	s.then([]() {

		/*
		 * moving on to the next test.
		 */
		_testing_multiple_tasks();
	});
}

/*
 * Task::run() function below does the following:
 * 1. Collects a bunch of tasks and their continuations.
 * 2. Runs each task on its own thread.
 * 3. On completion of each task,run its continuation on the current thread.
 * 4. Returns a future that holds all above tasks.
 * 5. .await() can be called on the future to suspend the current thread at a point
 *    where this medhod is called to wait for all tasks and their continuations to finish.
 * 6. .then() can be called on the future to register an event to be called when all
 *    tasks and their continuations finish.
 */
static void _testing_multiple_tasks_non_movable()
{
	_print("Testing multiple tasks without continuation arguments");

	auto fna1 = [a = std::unique_ptr<int>()](){ _printThreadID(); };
	auto fna2 = [a = std::unique_ptr<int>()](){ _printThreadID(); };
	auto fna3 = [a = std::unique_ptr<int>()](){ _printThreadID(); };

	auto ra1 = [a = std::unique_ptr<int>()](){ _print("r1"); };
	auto ra2 = [a = std::unique_ptr<int>()](){ _print("r2"); };
	auto ra3 = [a = std::unique_ptr<int>()](){ _print("r3"); };

	Task::future<void>& e = Task::run(Task::make_pair(std::move(fna1), std::move(ra1)),
		Task::make_pair(std::move(fna2), std::move(ra2)),
		Task::make_pair(std::move(fna3), std::move(ra3)));

	e.await();

	_print("Testing multiple tasks with continuation arguments");

	auto fn1 = [a = std::unique_ptr<int>()](){ _printThreadID(); return 0; };
	auto fn2 = [a = std::unique_ptr<int>()](){ _printThreadID(); return 0; };
	auto fn3 = [a = std::unique_ptr<int>()](){ _printThreadID(); return 0; };

	auto r1 = [a = std::unique_ptr<int>()](int){ _print("r1"); };
	auto r2 = [a = std::unique_ptr<int>()](int){ _print("r2"); };
	auto r3 = [a = std::unique_ptr<int>()](int){ _print("r3"); };

	Task::future<int>& s = Task::run(Task::make_pair(std::move(fn1), std::move(r1)),
		Task::make_pair(std::move(fn2), std::move(r2)),
		Task::make_pair(std::move(fn3), std::move(r3)));

	s.then(_testing_multiple_tasks_with_start);
}

static void _testing_multiple_tasks()
{
	_print("Testing multiple tasks without continuation arguments");

	auto fna1 = []() { _printThreadID(); };
	auto fna2 = []() { _printThreadID(); };
	auto fna3 = []() { _printThreadID(); };

	auto ra1 = []() { _print("r1"); };
	auto ra2 = []() { _print("r2"); };
	auto ra3 = []() { _print("r3"); };

	Task::future<void>& e = Task::run(Task::make_pair(fna1, ra1),
		Task::make_pair(fna2, ra2),
		Task::make_pair(fna3, ra3));

	e.await();

	_print("Testing multiple tasks with continuation arguments");

	auto fn1 = []() { _printThreadID(); return 0; };
	auto fn2 = []() { _printThreadID(); return 0; };
	auto fn3 = []() { _printThreadID(); return 0; };

	auto r1 = [](int) { _print("r1"); };
	auto r2 = [](int) { _print("r2"); };
	auto r3 = [](int) { _print("r3"); };

	Task::future<int>& s = Task::run(Task::make_pair(fn1, r1),
		Task::make_pair(fn2, r2),
		Task::make_pair(fn3, r3));

	s.then(_testing_multiple_tasks_non_movable);
}

static void _testing_multiple_tasks_with_start()
{
	std::cout << "Testing multiple tasks with continuation arguments using start" << std::endl;

	wait w;

	auto fn1 = []() { _printThreadID(); return 0; };
	auto fn2 = []() { _printThreadID(); return 0; };
	auto fn3 = []() { _printThreadID(); return 0; };

	auto r1 = [&](int) { w.task_finished("r1"); };
	auto r2 = [&](int) { w.task_finished("r2"); };
	auto r3 = [&](int) { w.task_finished("r3"); };

	Task::future<int>& s = Task::run(Task::make_pair(fn1, r1),
		Task::make_pair(fn2, r2),
		Task::make_pair(fn3, r3));

	s.start();

	w.loop.exec();

	QCoreApplication::quit();
}

static void _testing_queue_with_no_results()
{
	std::cout << "Testing queue with no result" << std::endl;

	auto fna1 = []() { _printThreadID(); };
	auto fna2 = []() { _printThreadID(); };
	auto fna3 = []() { _printThreadID(); };

	auto ra1 = []() { _print("r1"); };
	auto ra2 = []() { _print("r2"); };
	auto ra3 = []() { _print("r3"); };

	Task::future<void>& e = Task::run(Task::make_pair(fna1, ra1),
		Task::make_pair(fna2, ra2),
		Task::make_pair(fna3, ra3));

	e.queue(_testing_queue_with_results);
}

static void _testing_queue_with_results()
{
	std::cout << "Testing queue with result" << std::endl;

	auto fn1 = []() { _printThreadID(); return 0; };
	auto fn2 = []() { _printThreadID(); return 0; };
	auto fn3 = []() { _printThreadID(); return 0; };

	auto r1 = [=](int) { _print("r1"); };
	auto r2 = [=](int) { _print("r2"); };
	auto r3 = [=](int) { _print("r3"); };

	Task::future<int>& s = Task::run(Task::make_pair(fn1, r1),
		Task::make_pair(fn2, r2),
		Task::make_pair(fn3, r3));
	s.queue(_test_run_then);
}

static void _testing_checking_multiple_futures()
{
	auto fn1 = []() {};
	auto fn2 = []() {};
	auto fn3 = []() {};

	_print("Testing finding out if a future manages multiple futures");

	Task::future<void>& e = Task::run_tasks(fn1, fn2, fn3);

	const auto& z = e.all_threads();

	std::string s = e.manages_multiple_futures() ? "true" : "false";

	_print("A future managed multiple futures: " + s);
	_print("Number of future managed: " + QString::number(z.size()).toStdString());
}

static void _test_when_any1()
{
	_print("Testing when_any");

	wait w;

	auto ll1 = [&]() {

		QThread::currentThread()->sleep(5);
		w.task_finished("aaa");
	};

	auto ll2 = [&]() {

		QThread::currentThread()->sleep(2);
		w.task_finished("bbb");
	};

	auto ll3 = [&]() {

		QThread::currentThread()->sleep(3);
		w.task_finished("ccc");
	};

	Task::run_tasks(ll1, ll2, ll3).when_any([]() {

		_print("when_any called");
	});

	w.loop.exec();

	_print("Done testing when_any");
}

static void _test_when_any2()
{
	_print("Testing when_any with result");

	wait w;

	auto fn1 = [&]() {

		QThread::currentThread()->sleep(5);
		w.task_finished("aaa");
		return 0;
	};

	auto fn2 = [&]() {

		QThread::currentThread()->sleep(2);
		w.task_finished("bbb");
		return 0;
	};

	auto fn3 = [&]() {

		QThread::currentThread()->sleep(3);
		w.task_finished("ccc");
		return 0;
	};

	auto ff = [](int) {};

	Task::future<int>& s = Task::run(Task::make_pair(fn1, ff),
		Task::make_pair(fn2, ff),
		Task::make_pair(fn3, ff));

	s.when_any([]() {

		_print("when_any called");
	});

	w.loop.exec();

	_print("Done testing when_any with result");
}

static void _test_move_only_callables()
{
	Task::run([a = std::unique_ptr<int>()](int x){ return x; }, 4).get();
	Task::run([a = std::unique_ptr<int>()](int){}, 4).get();

	Task::run([a = std::unique_ptr<int>()](){ return 6; }).get();
	Task::run([a = std::unique_ptr<int>()](){}).get();

	Task::await([a = std::unique_ptr<int>()](){ return 6; });

	auto& tt = Task::run([a = std::unique_ptr<int>()](){ return 6; });

	Task::await(tt);
	Task::await(Task::run([a = std::unique_ptr<int>()](){}));

	Task::await([a = std::unique_ptr<int>()](int x){ return x; }, 4);

	Task::await([a = std::unique_ptr<int>()](int){}, 4);

	Task::await([a = std::unique_ptr<int>()](){ return 6; });

	Task::await([a = std::unique_ptr<int>()](){});

	auto& zz = Task::run([a = std::unique_ptr<int>()](){ return 6; });

	Task::await(zz);
	Task::await(Task::run([a = std::unique_ptr<int>()](){}));

	Task::exec([a = std::unique_ptr<int>()](int x){ return x; }, 4);
	Task::exec([a = std::unique_ptr<int>()](int){}, 4);

	Task::exec([a = std::unique_ptr<int>()](){ return 6; });
	Task::exec([a = std::unique_ptr<int>()](){});

	Task::run_tasks([a = std::unique_ptr<int>()](){ return 6; },
		[a = std::unique_ptr<int>()](){ return 6; },
		[a = std::unique_ptr<int>()](){ return 6; },
		[a = std::unique_ptr<int>()](){ return 6; }).get();

	Task::run_tasks([]() { return 6; },
		[]() { return 6; },
		[]() { return 6; },
		[]() { return 6; }).get();

	Task::run_tasks(Task::run([a = std::unique_ptr<int>()](){}),
		Task::run([a = std::unique_ptr<int>()](){}),
		Task::run([a = std::unique_ptr<int>()](){})).get();
}

static void _test_copyable_callables()
{
	auto aa = [](int x) { return x; };

	auto bb = []() {	return 6; };

	auto cc = []() {};

	auto dd = [](int) {};

	Task::run(aa, 4).get();
	Task::run(dd, 4).get();

	Task::run(bb).get();
	Task::run(cc).get();

	Task::await(bb);

	auto& tt = Task::run(bb);

	Task::await(tt);
	Task::await(Task::run(cc));

	Task::await(aa, 4);

	Task::await(dd, 4);

	Task::await(bb);

	Task::await(cc);

	auto& zz = Task::run(bb);

	Task::await(zz);
	Task::await(Task::run(cc));

	Task::exec(aa, 4);
	Task::exec(dd, 4);

	Task::exec(bb);
	Task::exec(cc);

	Task::run_tasks(bb, bb, cc).get();

	Task::run_tasks(Task::run(cc), Task::run(cc)).get();
}

struct foo
{
	foo()
	{
	}
	foo(int a)
	{
		_print(a);
	}
	std::unique_ptr<int> m;
};

struct www
{
	void operator()()
	{

	}
	www(const www&)
	{
		_print("const www&");
	}
	www(www&&)
	{
		_print("www&&");
	}
	www()
	{
		_print("www()");
	}
	www& operator=(const www&)
	{
		_print("www& operator=( const www& )");

		return *this;
	}
	www& operator=(www&&)
	{
		_print("www& operator=( www&& )");

		return *this;
	}

	std::unique_ptr<int> m;
};

void example::run()
{
#if __cplusplus >= 201703L

	Task::await([](foo, foo, foo) {}, foo(7), foo(7), foo(7));
#endif
	_test_copyable_callables();

	_test_move_only_callables();

	_test_when_any1();

	_test_when_any2();

	auto run_main = [](QVariant x) {

		std::cout << x.value<int>() << ": mm Thread id: " << QThread::currentThreadId() << std::endl;
	};

	auto run_bg = [](const Task::progress& pp) {

		for (int i = 0; i < 2; i++) {
			std::cout << i << ": bg Thread id: " << QThread::currentThreadId() << std::endl;
			pp.update(i);
			QThread::currentThread()->sleep(1);
		}
	};

	std::cout << "main Thread: " << QThread::currentThreadId() << std::endl;

	Task::future<void>& abc = Task::run(this, run_bg, run_main);

	abc.await();

	_testing_checking_multiple_futures();

	_testing_queue_with_no_results();
}

示例代码通过一系列测试函数展示了库的功能,主要测试流程如下:

  1. _test_run_then() - 测试基本任务链式调用

  2. _testing_task_await() - 测试同步等待任务完成

  3. _testing_task_future_all() - 测试多任务并行执行

  4. _testing_multiple_tasks() - 测试带回调的多任务

  5. _testing_multiple_tasks_with_start() - 测试手动启动多任务

  6. _testing_queue_with_no_results() - 测试无结果的串行队列

  7. _testing_queue_with_results() - 测试带结果的串行队列

  8. _testing_checking_multiple_futures() - 测试多future管理

2. 核心功能示例

2.1 基本任务链式调用 (_test_run_then)

Task::run([]() {
    return _longRunningTask();
}).then([](QString r) {
    _useResult(r);
});
  • run() 启动异步任务

  • then() 添加完成回调

  • 任务在后台线程执行,回调在主线程执行

2.2 同步等待 (_testing_task_await)

QString e = Task::await(_longRunningTask);
  • 非阻塞等待任务完成

  • 保持GUI响应

  • 返回任务结果

2.3 多任务并行 (_testing_task_future_all)

Task::future<void>& e = Task::run_tasks(fn1, fn2, fn3);
e.await(); // 等待所有任务完成
  • 多个任务并行执行

  • 可以等待所有任务完成

2.4 带回调的多任务 (_testing_multiple_tasks)

cpp

Task::future<int>& s = Task::run(
    Task::make_pair(fn1, r1),
    Task::make_pair(fn2, r2),
    Task::make_pair(fn3, r3)
);
  • 每个任务有自己的回调函数

  • 任务完成后执行对应的回调

2.5 串行队列 (_testing_queue_with_no_results)

Task::future<void>& e = Task::run(...);
e.queue(_testing_queue_with_results);
  • 任务按顺序执行

  • 前一个完成后才开始下一个

3. 高级功能

3.1 "when_any" 模式

Task::run_tasks(ll1, ll2, ll3).when_any([]() {
    _print("when_any called");
});
  • 任意一个任务完成即触发回调

  • 不等待其他任务

3.2 进度报告

Task::run(this, run_bg, run_main);
  • run_bg 在后台执行

  • 通过 progress 对象报告进度

  • run_main 在主线程处理进度更新

3.3 不可复制(unique)可调用对象支持

Task::run([a = std::unique_ptr<int>()](){ return 6; }).get();
  • 支持移动语义的lambda

  • 可以捕获unique_ptr等不可复制对象

4. 技术亮点

  1. Qt集成:深度利用Qt的事件循环和线程机制,适合Qt应用程序

  2. 灵活的任务组合:支持多种任务执行模式(并行、串行、任意完成)

  3. 类型安全:通过模板确保类型安全

  4. 异常安全:合理使用RAII管理资源

  5. 现代化C++:使用C++11/14/17特性如移动语义、lambda等

  6. 线程安全:使用 QMutex 保护共享数据

  7. 线程管理:自动管理 QThread 生命周期

5. 局限性

  1. 依赖Qt框架,不适合非Qt项目

  2. 错误处理机制相对简单

  3. 文档和示例不足(根据代码注释)

6. 总结

  1. 对于简单任务,使用 run().then() 链式调用

  2. 需要同步结果时使用 await()

  3. 多个独立任务使用 run_tasks()

  4. 任务间有依赖时使用 queue()

  5. 需要进度反馈时使用 progress 对象

这个Task库提供了一个强大而灵活的异步任务处理框架,特别适合需要与Qt GUI集成的应用程序。它通过精心设计的模板类和Qt的线程机制,实现了高效、易用的异步编程模型。虽然有一些局限性,但对于Qt开发者来说,这是一个非常有价值的工具。

代码中的模板元编程和设计模式值得学习,特别是如何将标准库的future概念与Qt框架相结合的设计思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值