1. 程式人生 > >std::async 實現鏈式呼叫

std::async 實現鏈式呼叫

    c#和java中都有直接提供方法實現非同步執行一個任務,並在其執行完成後執行指定的任務。然而c++11卻沒有直接提供類似的實現。雖然用c++98的泛型和直接使用系統執行緒也能實現,不過要實現好還是很複雜。現在有了c++11,就可以用其中的 std::async 和 lambda方便地實現了。

    在前面的任務執行完成後,可能會返回一個值,也可能不會返回值,後續的任務雖然大部分情況都需要使用到返回的值但也可以選擇性忽略返回值。因此提供了兩個函式,一個將當前返回值傳給下一個函式,另一個忽略返回值。

實現:

#ifndef __ASYNC_TASK
#define __ASYNC_TASK

#include <functional>
#include <future>
#include <utility>

template <typename T>
class Task;

template <typename R, typename... Args>
class Task < R(Args...) >
{
public:
	using return_type = R;

	template <typename F, typename... exArgs>
	auto then(F&& f, exArgs&&... args) -> Task < typename std::result_of<F(exArgs...)>::type(void) >
	{
		using thRType = typename std::result_of<F(exArgs...)>::type;
		auto func = std::move(m_fn);
		auto thFn = std::bind(std::forward<F>(f), std::forward<exArgs>(args)...);
		return Task<thRType(void)>([func, thFn]() mutable
		{
			func();
			return thFn();
		});
	}

	template <typename F>
	auto passthen(F&& f) -> Task < typename std::result_of<F(R)>::type(void) >
	{
		using thRType = typename std::result_of<F(R)>::type;
		auto func = std::move(m_fn);
		auto thFn = std::forward<F>(f);
		return Task<thRType(void)>([func, thFn]() mutable
		{
			return thFn(func());
		});
	}

	R get()
	{
		return std::async(std::launch::deferred, m_fn).get();
	}
	void wait()
	{
		std::async(std::launch::deferred, m_fn).wait();
	}
	std::future<R> async(std::launch launchmode)
	{
		return std::async(launchmode, m_fn);
	}

	//constractors
	template<typename... FnArgs>
	Task(const std::function<R(Args...)>& f, FnArgs&&... args)
	{
		m_fn = std::bind(f, std::forward<FnArgs>(args)...);
	}
	~Task() = default;

	Task(Task &&other)
	{
		m_fn = std::move(other.m_fn);
	}
	Task& operator=(Task &&other)
	{
		m_fn = std::move(other.m_fn);
		return *this;
	}

private:
	Task() = delete;
	Task(const Task&) = delete;
	Task& operator=(const Task&) = delete;
private:
	std::function<R(void)> m_fn;
};

#endif

測試:

#include <iostream>
#include "AsyncTask.h"

int acallback(int sigarg)
{
	std::cout << "a callback arg:" << sigarg << std::endl;
	return sigarg * 2;
}
int bcallback()
{
	std::cout << "b callback withoutarg:" << std::endl;
	return -1;
}
void ccallback(int sigarg)
{
	std::cout << "c callback arg:" << sigarg << std::endl;
}
void dcallback()
{
	std::cout << "d callback withoutarg:" << std::endl;
}
void ecallback(int arg1, int arg2)
{
	std::cout << "e callback arg:" << arg1 <<',' <<arg2 << std::endl;
}

class callObj
{
public:
	callObj(int a, int b) : a_(a), b_(b) {}
	int operator()()
	{
		return a_ + b_;
	}
	~callObj() {}
private:
	int a_;
	int b_;
};

int main()
{
	//auto sometask1 = Task<int(int)>(acallback, 5).then(callObj(2,3));
	//auto sometask1 = Task<int(int)>(acallback, 5).passthen(std::bind(ecallback, 8, std::placeholders::_1));
	auto sometask1 = Task<int(int)>(acallback, 5).passthen([](int val) { std::cout << val << " lambda\n"; });
	sometask1.async(std::launch::async).get();

	return 0;
}