๐งต C++ Threading Basics: The Kitchen Story
Imagine youโre the head chef in a busy restaurant. You have ONE kitchen, but MANY dishes to prepare. What if you could have multiple cooks working at the same time?
๐ณ What is a Thread?
Think of your program as a restaurant kitchen.
- The kitchen = your computerโs CPU
- The head chef = your main program
- Helper cooks = threads!
Without threads, the head chef does EVERYTHING alone. With threads, multiple cooks work at the same time!
#include <thread>
#include <iostream>
// This is like a cook's recipe
void cookPasta() {
std::cout << "Cooking pasta...\n";
}
int main() {
// Hire a helper cook!
std::thread helper(cookPasta);
helper.join();
return 0;
}
๐ Creating Threads
The Simple Truth: Creating a thread is like hiring a new cook and giving them a recipe to follow.
Method 1: Using a Function
#include <thread>
#include <iostream>
void sayHello() {
std::cout << "Hello from thread!\n";
}
int main() {
std::thread t(sayHello);
t.join();
return 0;
}
Method 2: Using a Lambda
#include <thread>
#include <iostream>
int main() {
std::thread t([]() {
std::cout << "Hello from lambda!\n";
});
t.join();
return 0;
}
๐ก Key Points
| What | Meaning |
|---|---|
std::thread t(func) |
Hire cook, give recipe |
t.join() |
Wait for cook to finish |
t.detach() |
Let cook work alone |
๐ค Joining Threads
Story Time: Imagine the head chef needs the pasta BEFORE serving. They must WAIT for the helper to finish.
void cookPasta() {
// Takes 5 seconds
std::this_thread::sleep_for(
std::chrono::seconds(2));
std::cout << "Pasta ready!\n";
}
int main() {
std::thread pasta(cookPasta);
std::cout << "Waiting for pasta...\n";
pasta.join(); // WAIT here!
std::cout << "Now I can serve!\n";
return 0;
}
What Happens?
graph TD A["Main starts"] --> B["Create pasta thread"] B --> C["Main waits at join"] B --> D["Pasta cooks..."] D --> E["Pasta done!"] E --> F["Main continues"] C --> F
โ ๏ธ Rule #1
ALWAYS join or detach a thread before it goes out of scope!
If you forget, your program CRASHES! ๐ฅ
๐ฆ Detaching Threads
Different Story: Sometimes the helper cook makes bread for tomorrow. You donโt need to wait!
void bakeBread() {
std::this_thread::sleep_for(
std::chrono::hours(2));
std::cout << "Bread ready!\n";
}
int main() {
std::thread bread(bakeBread);
bread.detach(); // Go work alone!
// Main continues immediately
std::cout << "I'm not waiting!\n";
return 0;
}
Join vs Detach
| Join ๐ค | Detach ๐ฆ |
|---|---|
| Wait for thread | Donโt wait |
| Know when done | Donโt know |
| Safe & controlled | Runs freely |
| Like waiting for pizza | Like ordering delivery |
โ ๏ธ Warning!
Once detached, you LOSE control. The thread runs until:
- It finishes naturally, OR
- The program ends
๐ฆ Thread Arguments
The Fun Part: What if the cook needs ingredients? Pass them as arguments!
Passing Simple Values
void greet(std::string name) {
std::cout << "Hello, " << name << "!\n";
}
int main() {
std::thread t(greet, "Alice");
t.join();
return 0;
}
Passing Multiple Arguments
void cook(std::string dish, int mins) {
std::cout << "Cooking " << dish
<< " for " << mins << " mins\n";
}
int main() {
std::thread t(cook, "Pizza", 15);
t.join();
return 0;
}
๐ฏ Passing by Reference
Tricky Part: Threads COPY arguments by default!
void addOne(int& num) {
num = num + 1;
}
int main() {
int x = 5;
// WRONG - x won't change!
// std::thread t(addOne, x);
// RIGHT - use std::ref()
std::thread t(addOne, std::ref(x));
t.join();
std::cout << x << "\n"; // Prints 6!
return 0;
}
๐ Argument Rules
| Want toโฆ | Use this |
|---|---|
| Pass a copy | Just pass it |
| Pass a reference | Use std::ref(var) |
| Pass a pointer | Just pass it |
๐ช The Complete Picture
graph TD A["Main Thread"] --> B{Create Thread} B --> C["Thread runs function"] B --> D{Choose action} D --> E["join - Wait"] D --> F["detach - Let go"] E --> G["Thread done"] G --> H["Main continues"] F --> I["Main continues immediately"] C --> J["Thread finishes eventually"]
๐ Quick Summary
Creating Threads
std::thread t(function); // Basic
std::thread t(func, arg1); // With args
std::thread t([](){/*...*/}); // Lambda
Managing Threads
t.join(); // Wait for it
t.detach(); // Let it go
t.joinable(); // Can I join/detach?
Passing Arguments
std::thread t(func, value); // Copy
std::thread t(func, std::ref(x)); // Reference
๐ญ Remember the Kitchen!
| Concept | Kitchen Analogy |
|---|---|
| Thread | Helper cook |
| join() | Wait for dish |
| detach() | Work independently |
| Arguments | Ingredients |
| Main thread | Head chef |
๐ You Did It!
You now understand:
- โ How to create threads
- โ When to join (wait)
- โ When to detach (let go)
- โ How to pass data to threads
Next adventure: Protecting your kitchen from chaos with mutexes! ๐
Happy threading! ๐งต
