C++ 11 thread promise, future, async, packaged_task

1.promise and future

The function of future and promise is to pass data between different threads. The pointer can also be used to transfer data, but the pointer is very dangerous, because the mutual exclusion cannot prevent the access of the pointer; moreover, the data transferred by the pointer is fixed. If you change the data type, you need to change the relevant interface, which is more troublesome; promise supports generic operation, which is more convenient for programming.

Assuming that thread 1 needs the data of thread 2, the combined usage is as follows:

Thread 1 initializes a promise object and a future object. Promise is passed to thread 2, which is equivalent to thread 2's promise to thread 1. Future is equivalent to accepting a promise to get the value passed by thread 2 in the future
After thread 2 obtains the promise, it needs to pass relevant data to the promise, and then the future of thread 1 can get the data.
If thread 1 wants to get data and thread 2 doesn't give it, thread 1 blocks until thread 2's data arrives.

As long as thread 1 detects the arrival of data, get can return, and the state of thread 2 can end or continue to run.

// threadTest.cpp: defines the entry point for the console application.
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

// Calculate the sum of a vector array and set a promise. This is a promise. You need to set this value
void accumulate(std::vector<int>::iterator first,
	std::vector<int>::iterator last,
	std::promise<int> accumulate_promise)
{
	int sum = std::accumulate(first, last, 0);
	std::cout << "set promise\n";
	accumulate_promise.set_value(sum);// Notify future
	std::this_thread::sleep_for(std::chrono::seconds(10));
}

void do_work(std::promise<void> barrier)
{
	std::this_thread::sleep_for(std::chrono::seconds(1));
	barrier.set_value();
	std::this_thread::sleep_for(std::chrono::seconds(10));
}

int main()
{
	// Demonstrate using promise<int> to transmit a result between threads.
	std::vector<int> numbers = { 1,2,3,4,5,6 };
	std::promise<int> accumulate_promise;
	std::future<int> accumulate_future = accumulate_promise.get_future();
	std::thread work_thread(accumulate, numbers.begin(), numbers.end(), std::move(accumulate_promise));

	std::cout << "result=" << accumulate_future.get() << "\n";
	work_thread.join();

	std::promise<void> barrier;
	std::future<void> barrier_future = barrier.get_future();
	std::thread new_work_thread(do_work, std::move(barrier));
	barrier_future.wait();
	new_work_thread.join();
    return 0;
}

 

2.async

(advanced packaging future and thread)

runs a function asynchronously (potentially in a new thread) and returns a std::future that will hold the result

Run a function asynchronously (possibly in a new thread) and return STD:: future that will hold the result

// threadTest.cpp: defines the entry point for the console application.
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

bool is_prime(int x)
{
	for (int i = 2; i < x; i++) {
		if (x%i == 0)
			return false;
	}
	return true;
}

int main()
{
	// call function asynchronously;
	std::future<bool> fut = std::async(is_prime, 4444444443);

	// do something while waiting for function to set future.
	std::cout << "checking,please wait...";
	std::chrono::milliseconds span(100);
	while (fut.wait_for(span) == std::future_status::timeout)
	{
		std::cout << '.' << std::flush;
	}
	bool x = fut.get();
	std::cout << "\n4444444443 " << (x ? "is" : "is not") << " prime.\n";

    return 0;
}

Operation result:

std::async will first create a thread to execute is prime (4444444443). After the task is created, std::async will immediately return an std::future object.

The main thread can use std::future::get to get the result. If the task is not completed during the call, the main thread will block until the task is completed.

The main thread can also use STD:: Future:: wait for to wait for the result to return. Wait for can set the timeout. If the task is completed within the timeout, the status of STD:: future UU status:: ready will be returned. If the task is not completed within the timeout, the status of STD:: future UU status:: timeout will be returned.

3.packaged_task

The function of std::packaged_task is to provide a data synchronization mechanism between different threads. It can store a function operation and pass its return value to the corresponding future, which can also be accessed safely in another thread.

Example code:

// threadTest.cpp: defines the entry point for the console application.
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

int countdown(int from, int to)
{
	for (int i = from; i != to; --i)
	{
		std::cout << i << '\n';
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
	std::cout << "Lift off!\n";
	return from - to;
}

int main()
{
	std::packaged_task<int(int, int)> tsk(countdown);
	std::future<int> ret = tsk.get_future();
	std::thread th(std::move(tsk), 10, 0);
	// ...
	int value = ret.get();// wait for the task to finish and get result
	std::cout << "The countdown lasted for " << value << " seconds.\n";
	th.join();
    return 0;
}

Operation result:

251 original articles published, 20 praised, 80 thousand visitors+
Private letter follow

Tags: Programming

Posted on Thu, 12 Mar 2020 05:11:58 -0400 by bobleny