You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: lectures/parallelism.md
+87-24Lines changed: 87 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,7 +39,45 @@ With that out of the way, one of the safest way to do concurrency in modern C++
39
39
40
40
If we have such a heavy task to run, we can use [`std::async`](https://en.cppreference.com/w/cpp/thread/async.html). This function takes a callable (like a [lambda](lambdas.md)) and a [launch policy](https://en.cppreference.com/w/cpp/thread/launch.html), and runs it asynchronously, potentially on a background thread. It returns a `std::future`, which is basically a promise similar to "I don't have the result now, but I will in the *future*."
41
41
42
-
For the sake of example, let's say our application needs to load a massive image from disk, but we also want to keep the UI responsive and draw a progress bar:
42
+
For the sake of example, let's say our application needs to load a massive image from disk (which we will here simulate by sleeping for 5 seconds) but we also want to keep the UI responsive and draw a loading spinner. Let's first see what happens if we just load the image on the main thread:
43
+
44
+
<!--
45
+
`CPP_SETUP_START`
46
+
$PLACEHOLDER
47
+
`CPP_SETUP_END`
48
+
`CPP_COPY_SNIPPET` parallelism_blocking/main.cpp
49
+
`CPP_RUN_CMD` CWD:parallelism_blocking c++ -std=c++17 main.cpp
50
+
-->
51
+
```cpp
52
+
#include<chrono>
53
+
#include<iostream>
54
+
#include<string>
55
+
#include<thread>
56
+
57
+
structImage {
58
+
std::string data = "massive_8k_image_data";
59
+
};
60
+
61
+
Image LoadMassiveImage() {
62
+
// Pretend this takes a long time to load a massive image.
// 😱 The main thread is completely frozen here for 5 seconds.
70
+
// We can't update any UI, draw a spinner, or do anything else!
71
+
const Image img = LoadMassiveImage();
72
+
std::cout << " Done!\n";
73
+
std::cout << "Image loaded successfully!\n";
74
+
return 0;
75
+
}
76
+
```
77
+
78
+
When we run this, the application just prints "Loading massive image..." and then hangs for 5 full seconds with no sign of life. The main thread is completely blocked. There is no way for us to draw a spinner or update any other UI element while the image is loading. To the user, the application looks frozen — and that's because it *is* frozen.
79
+
80
+
Let's fix this! We can use `std::async` to kick off the heavy `LoadMassiveImage` function on a background thread, freeing the main thread to update the UI. While we're at it, let's encapsulate our spinner logic into a reusable `Spinner` class:
// Wait for the result (blocks main thread, but the spinner
155
+
// keeps animating on its own thread).
97
156
const Image img = future_image.get();
157
+
158
+
// ✅ Stop the spinner and show the result!
159
+
spinner.Stop("✅ Loading massive image... Done!");
98
160
std::cout << "Image loaded successfully!\n";
99
161
return 0;
100
162
}
101
163
```
102
164
103
165
Here, we do the following:
104
-
1. We use `std::async` to start the heavy `LoadMassiveImage` function on a background thread, which returns a `std::future` that holds a promise of a result.
105
-
2. We use `wait_for` with a short timeout to check if the task is finished without blocking the main thread.
106
-
3. We execute UI logic (the loading spinner in our case) in the main thread while the background thread is busy.
107
-
4. We call `.get()` to synchronize and retrieve the final `Image` data once the task is ready.
166
+
1. We first see that loading a massive image *without* parallelism completely freezes the main thread — no spinner, no UI updates, nothing.
167
+
2. We fix that by using `std::async` to start the heavy `LoadMassiveImage` function on a background thread, which returns a `std::future` that holds a promise of the result.
168
+
3. We encapsulate the spinner animation in a `Spinner` class that runs on its own thread, using `std::atomic<bool>` for thread-safe signaling.
169
+
4. We call `.get()` on the future to wait for and retrieve the final `Image` data, while the spinner keeps animating independently.
170
+
5. Once the image is loaded, we call `spinner.Stop()` to cleanly shut down the animation thread and display the final message.
0 commit comments