C++ async & launch | "Asynchronous Execution" Guide
이 글의 핵심
std::async and std::launch policies: async vs deferred, thread creation, and when futures block—C++11 concurrency patterns with std::future.
What is std::async?
std::async is a C++11 API that executes a function asynchronously and retrieves the result using a future. The result can also be shared using promise·future and shared_future. If you’re familiar with thread basics, it’s easy to use.
#include <future>
auto future = std::async([]() {
return 42;
});
int result = future.get(); // Wait for the result
launch Policies
Comparison of launch Policies
| Policy | Execution Timing | Thread Creation | Use Case |
|---|---|---|---|
| launch::async | Immediately | ✅ New thread | CPU-intensive tasks |
| launch::deferred | On get() call | ❌ Current thread | Conditional execution |
| async | deferred | Implementation-defined | Auto-selected | General use |
// async: New thread
auto f1 = std::async(std::launch::async, func);
// deferred: Delayed execution
auto f2 = std::async(std::launch::deferred, func);
// Default: async | deferred
auto f3 = std::async(func);
Execution Flow by Policy
sequenceDiagram
participant Main as Main Thread
participant Async as Async Thread
Note over Main: launch::async
Main->>Async: start immediately
Main->>Main: other work
Async->>Async: background exec
Main->>Async: future.get()
Async->>Main: return result
Note over Main: launch::deferred
Main->>Main: async call (no exec)
Main->>Main: other work
Main->>Main: future.get()
Main->>Main: exec func now
Main->>Main: return result
Practical Examples
Example 1: Basic Usage
#include <future>
#include <iostream>
int compute(int x) {
std::this_thread::sleep_for(std::chrono::seconds(1));
return x * x;
}
int main() {
auto future = std::async(compute, 10);
std::cout << "Computing..." << std::endl;
int result = future.get(); // Wait
std::cout << "Result: " << result << std::endl; // 100
}
Example 2: Multiple Asynchronous Tasks
auto f1 = std::async([]() { return compute1(); });
auto f2 = std::async([]() { return compute2(); });
auto f3 = std::async([]() { return compute3(); });
// Parallel execution
int r1 = f1.get();
int r2 = f2.get();
int r3 = f3.get();
int total = r1 + r2 + r3;
Parallel Execution Timeline:
gantt
title Parallel vs Sequential Execution Comparison
dateFormat X
axisFormat %L
section Parallel (async)
compute1 :0, 1000
compute2 :0, 1000
compute3 :0, 1000
section Sequential Execution
compute1 :0, 1000
compute2 :1000, 2000
compute3 :2000, 3000
Performance Comparison:
| Execution Mode | Task Duration | Total Time | Performance Gain |
|---|---|---|---|
| Sequential Execution | 1 sec × 3 | 3 sec | - |
| Parallel Execution (async) | 1 sec (concurrent) | 1 sec | 3x |
Example 3: launch Policies
// Immediate execution (new thread)
auto f1 = std::async(std::launch::async, []() {
std::cout << "Asynchronous execution" << std::endl;
return 42;
});
// Delayed execution (on get call)
auto f2 = std::async(std::launch::deferred, []() {
std::cout << "Deferred execution" << std::endl;
return 42;
});
f2.get(); // Executes here
Example 4: Exception Handling
auto future = std::async([]() {
throw std::runtime_error("Error");
return 42;
});
try {
int result = future.get(); // Rethrows exception
} catch (const std::exception& e) {
std::cout << "Exception: " << e.what() << std::endl;
}
Checking future Status
auto future = std::async(std::launch::async, compute);
// Wait
future.wait();
// Timeout
auto status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::ready) {
std::cout << "Completed" << std::endl;
} else if (status == std::future_status::timeout) {
std::cout << "Timeout" << std::endl;
}
Common Issues
Issue 1: Future Destruction
// ❌ Ignoring future
std::async([]() {
// Task
}); // Blocks in destructor
// ✅ Store the future
auto future = std::async([]() {
// Task
});
Issue 2: Multiple get Calls
auto future = std::async([]() { return 42; });
int r1 = future.get(); // OK
// int r2 = future.get(); // Error: get already called
// get can only be called once
Issue 3: Exception Propagation
auto future = std::async([]() {
throw std::runtime_error("Error");
});
// Exception is thrown on get call
try {
future.get();
} catch (...) {
// Handle exception
}
Issue 4: Deadlock
// ❌ Potential deadlock
std::mutex mtx;
auto future = std::async([&mtx]() {
std::lock_guard<std::mutex> lock(mtx);
// ...
});
std::lock_guard<std::mutex> lock(mtx);
future.get(); // Deadlock
async vs thread
// std::async: Simple, returns future
auto future = std::async([]() { return 42; });
int result = future.get();
// std::thread: Manual management
std::thread t([]() {
// Hard to return result
});
t.join();
FAQ
Q1: When to use std::async?
A: When you need to execute a function asynchronously and retrieve its result.
Q2: What are the launch policies?
A:
- async: New thread
- deferred: Delayed execution
Q3: get vs wait?
A:
- get: Returns the result
- wait: Only waits for completion
Q4: How to handle exceptions?
A: Exceptions are rethrown when get is called.
Q5: Performance considerations?
A: Thread creation has overhead. For small tasks, this overhead might outweigh the benefits.
Q6: Resources for learning async?
A:
- “C++ Concurrency in Action”
- “Effective Modern C++”
- cppreference.com
Related Posts: future and promise, shared_future, Thread Basics, packaged_task.