C++11 Multithreading – Part 10: packaged_task<> Example and Tutorial

In this example we will discuss c++11 std::packaged_task feature and its uses.

std::packaged_task<> Details

std::packaged_task<> is a class template and represents a asynchronous task. It encapsulates,

  1. A callable entity i.e either function, lambda function or function object.
  2. A shared state that stores the value returned or thrown exception by associated callback.

Need of std::packaged_task<>

Suppose we have an existing function that fetches the data from DB and return i.e.

// Fetch some data from DB
std::string getDataFromDB( std::string token)
{
	// Do some stuff to fetch the data
	std::string data = "Data fetched from DB by Filter :: " + token;
	return data;
}

Now we want to execute this function in a separate thread. But how we will fetch the result or exception back in main thread after other thread is finished ?

One way is to change the declaration of function and pass a std::promise<> in the function. Before passing the std::promise<> object in thread function, fetch the associated std::future<> out of it and keep that in main thread. Now, before thread function returns its value, it should set that in passed std::promise<> argument, so that it can be available in associated std::future<> object in main thread. Check below tutorial for this approach i.e,

C++11 Multithreading &#8211; Part 8: std::future , std::promise and Returning values from Thread

But creating this std::promise<> and changing function code can be prevented if we use std::packaged_task<>.

Using packaged_task<> with function to create Asynchronous tasks

std::packaged_task<> can wrap around a normal function and make it applicable to run as asynchronous function.

When std::packaged_task<> is called in a separate thread, it calls the associated callback and stores the return  value/exception in its internal shared state. This value can be accessed in other thread or main function through std::future<> object.

Let’s create a std::packaged_task<> from above mentioned function, execute in separate thread and fetch result from its future<> object.

Creating std::packaged_task<> object

std::package_task<> is a class template, therefore we need to pass template parameter to packaged_task<> i.e. type of callable function

// Create a packaged_task<> that encapsulated the callback i.e. a function
std::packaged_task<std::string (std::string)> task(getDataFromDB);

Fetch the future object from it,

// Fetch the associated future<> from packaged_task<>
std::future<std::string> result = task.get_future();

Passing packaged_task<> to a thread,

std::packaged_task<> is movable but not copy-able, so we need to move it to thread i.e.

// Pass the packaged_task to thread to run asynchronously
std::thread th(std::move(task), "Arg");

As packaged_task was only movable and not copy-able, therefore we fetched the std::future<> object from it before moving it to thread.

Thread will execute this task, which internally calls associated callable entity i.e. our function getDataFromDB().

Now when this function returns the value, std::packaged_task<> sets it to associated shared state and result or exception returned by getDataFromDB() will eventually be available in associated future object.

In main function, fetch result from future<> object i.e.

// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
std::string data =  result.get();

get() function will block the calling thread until the callable entity returns and std::packaged_task<> set the data in its shareable state.

Complete example is as follows,

#include <iostream>
#include <thread>
#include <future>
#include <string>

// Fetch some data from DB
std::string getDataFromDB( std::string token)
{
	// Do some stuff to fetch the data
	std::string data = "Data fetched from DB by Filter :: " + token;
	return data;
}

int main()
{

	// Create a packaged_task<> that encapsulated the callback i.e. a function
	std::packaged_task<std::string (std::string)> task(getDataFromDB);

	// Fetch the associated future<> from packaged_task<>
	std::future<std::string> result = task.get_future();

	// Pass the packaged_task to thread to run asynchronously
	std::thread th(std::move(task), "Arg");

	// Join the thread. Its blocking and returns when thread is finished.
	th.join();

	// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
	std::string data =  result.get();

	std::cout <<  data << std::endl;

	return 0;
}

Output:

Data fetched from DB by Filter :: Arg

On similar lines we can create a packaged_task with lambda function and function objects too i.e.

Creating packaged_task with Lambda Function

#include <iostream>
#include <thread>
#include <future>
#include <string>

int main()
{

	// Create a packaged_task<> that encapsulated a lambda function
	std::packaged_task<std::string (std::string)> task([](std::string token){
		// Do some stuff to fetch the data
			std::string data = "Data From " + token;
			return data;
	});

	// Fetch the associated future<> from packaged_task<>
	std::future<std::string> result = task.get_future();

	// Pass the packaged_task to thread to run asynchronously
	std::thread th(std::move(task), "Arg");

	// Join the thread. Its blocking and returns when thread is finished.
	th.join();

	// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
	std::string data =  result.get();

	std::cout <<  data << std::endl;

	return 0;
}


Output:

Data fetched from DB by Filter :: Arg

 Creating packaged_task with Function Object

#include <iostream>
#include <thread>
#include <future>
#include <string>

/*
 * Function Object to Fetch Data from DB
 */
struct DBDataFetcher
{
	std::string operator()(std::string token)
	{
		// Do some stuff to fetch the data
					std::string data = "Data From " + token;
					return data;
	}
};

int main()
{

	// Create a packaged_task<> that encapsulated a lambda function
	std::packaged_task<std::string (std::string)> task(std::move(DBDataFetcher()));

	// Fetch the associated future<> from packaged_task<>
	std::future<std::string> result = task.get_future();

	// Pass the packaged_task to thread to run asynchronously
	std::thread th(std::move(task), "Arg");

	// Join the thread. Its blocking and returns when thread is finished.
	th.join();

	// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
	std::string data =  result.get();

	std::cout <<  data << std::endl;

	return 0;
}

 

Output:

Data fetched from DB by Filter :: Arg

2 thoughts on “C++11 Multithreading – Part 10: packaged_task<> Example and Tutorial”

  1. Kobi Cohen-Arazi

    Probably a typo here:
    std::packaged_task is movable but copy-able, so we need to move it to thread i.e.
    might be:
    std::packaged_task is movable but not copy-able, so we need to move it to thread i.e.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top