...

/

Use std::async for Concurrency

Use std::async for Concurrency

Learn to use std::async for concurrency.

We'll cover the following...

std::async() runs a target function asynchronously and returns a std::future object to carry the target function's return value. In this way, async() operates much like std::thread but allows return values.

Let's consider the use of std::async() with a few examples.

How to do it

In its simplest forms, the std::async() function performs much the same task as std::thread, without the need to call join() or detach() and while also allowing return values via a std::future object.

In this recipe, we'll use a function that counts the number of primes in a range. We'll use chrono::steady_clock to time the execution of each thread.

  • We'll start with a couple of convenience aliases:

using launch = std::launch;
using secs = std::chorno::duration<double>;

std::launch has launch policy constants, for use with the async() call.

The secs alias is a duration class, for timing our prime number calculations.

  • Our target function counts prime numbers in a range. This is essentially a way to understand the execution policies by eating some clock cycles:

struct prime_time {
secs dur{};
uint64_t count{};
};
prime_time count_primes(const uint64_t& max) {
prime_time ret{};
constexpr auto isprime = [](const uint64_t& n) {
for(uint64_t i{ 2 }; i < n / 2; ++i) {
if(n % i == 0) return false;
}
return true;
};
uint64_t start{ 2 };
uint64_t end{ max };
auto t1 = steady_clock::now();
for(uint64_t i{ start }; i <= end ; ++i) {
if(isprime(i)) ++ret.count;
}
ret.dur = steady_clock::now() - t1;
return ret;
}

The prime_time structure is for the return value, with elements for duration and count. This allows us to time the loop itself. The isprime lambda returns true if a value is prime. We use steady_clock to calculate the duration of the loop that counts primes.

  • In main(), we call our function and report its timing:

int main() {
constexpr uint64_t MAX_PRIME{ 0x1FFFF };
auto pt = count_primes(MAX_PRIME);
cout << format("primes: {} {:.3}\n", pt.count, pt.dur);
}

Output:

primes: 12252 1.88008s
  • Now, we can run count_primes() asynchronously with std::async():

int main() {
constexpr uint64_t MAX_PRIME{ 0x1FFFF };
auto primes1 = async(count_primes, MAX_PRIME);
auto pt = primes1.get();
cout << format("primes: {} {:.3}\n", pt.count, pt.dur);
}

Here, we call async() with ...