5

I am trying to understand how exactly async differs from using threads. On a conceptual level, I thought multithreading was by definition asynchronous, because you are doing context switches between threads for things like I/O.

But it seems that even for instances like single-threaded applications, just adding threads would be the same as using async. For example:

#include <iostream>       // std::cout
#include <future>         // std::async, std::future

// a non-optimized way of checking for prime numbers:
bool is_prime (int x) {
  std::cout << "Calculating. Please, wait...\n";
  for (int i=2; i<x; ++i) if (x%i==0) return false;
  return true;
}

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

  std::cout << "Checking whether 313222313 is prime.\n";
  // ...

  bool ret = fut.get();      // waits for is_prime to return

  if (ret) std::cout << "It is prime!\n";
  else std::cout << "It is not prime.\n";

  return 0;
}

Why can't I just create a thread to call is_prime that writes to some variable, and then call join() before I print that variable? If I can do this, what really is the benefit of using async? Some specific examples would be very helpful.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
Victor M
  • 603
  • 4
  • 22
  • You could create a thread, but that doesn't give you any inherent way to synchronize with it. I.e. you'd also need a mutex, and/or a condition variable, etc in order to know the calculation in the thread finished. `std::async` takes care of that for you. That's not to say it's always the right choice, but if you simply want to calculate a one-off result in parallel to your "main" code it's certainly convenient. – AVH Mar 25 '21 at 16:14
  • https://stackoverflow.com/questions/25814365/when-to-use-stdasync-vs-stdthreads – Hatted Rooster Mar 25 '21 at 16:15

1 Answers1

2

This is not C++ specific, so I try to be a little bit generic. I'm sure there are C++ specific quirks as well.

Generally speaking, yes. You could just create a variable for the output, start a thread, give the address of the variable to the thread and later .join the thread and access the variable after the thread wrote to it. That works. Nothing wrong with it. We did that for many years.

But as the program gets more complicated, this gets more and more messy. More and more thread to keep running, more and more variables to keep in mind when and how to access them safely. Can I print i here, or do I need to .join a specific thread first? Who knows.

Futures (or Promises or Tasks) and async/await is a pattern many languages use nowadays under those or very similar names. They don't do anything we could not do before, but they make it a lot easier to maintain when the program grows and is no longer this one page example program that everybody can read on one screen.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • `This is not C++ specific` - how so? – SergeyA Mar 25 '21 at 16:18
  • Probably because threads and async have nothing to do with C++, per se. Many languages have these abstractions. – ggorlen Mar 25 '21 at 16:19
  • I disagree. This is all about `std::thread`, `std::async`, `std::future`, etc – SergeyA Mar 25 '21 at 16:19
  • @SergeyA Excuse me, did you even read my post? **" is a pattern many languages use nowadays under those or very similar names"** – nvoigt Mar 25 '21 at 16:19
  • @SergeyA And my answer is *wrong* for C++? I'm waiting for your elaborate answer on how `std::future` is fundamentally different from `Future<>` and `std::async` is fundamentally different from `async`. A concept can apply to multiple languages, C++ is really not a unique programming language at all... it's actually pretty late to this specific pattern. – nvoigt Mar 25 '21 at 16:20
  • @SergeyA yes, those are C++'s implementation of these concepts but OP is asking a general question about what the difference is on a conceptual level, which seems language agnostic. – ggorlen Mar 25 '21 at 16:20
  • Yes, I believe, your answer is too generic and quite controversial as well. For example, C++ certainly **does not** skew towards using async calls - people either use thread pools, for which no C++ abstraction exists, or use threads directly, which give more control. On a more general note, the tag is clearly stated as C++, so I believe, answer has to be C++ specific. – SergeyA Mar 25 '21 at 16:26
  • The answer *applies* to C++, so I don't see why it must be C++ specific. Again, I am waiting for your advice on what is actually *wrong* with it, apart from the fact that I prefixed it with the information that other languages do the same. – nvoigt Mar 25 '21 at 16:28
  • @SergeyA `co_await` is now a (contextual) keyword in C++. Yes, we are yet to have *standardised* types that use it. – Caleth Mar 25 '21 at 16:34
  • @Caleth no arguments here, but how would it be relevant to the question about threads? (aside from general notion that under certain conditions threads could be instead replaced with coroutines)? – SergeyA Mar 25 '21 at 16:36