Introduction
Multithreading in C++ allows a program to run multiple threads concurrently. This can significantly improve performance, particularly on multicore processors, by allowing different parts of a program to execute simultaneously. C++11 introduced a standardized way to handle threads via the <thread> library, providing robust tools to create, manage, and synchronize threads.
Basic Concepts
- Thread: A thread is the smallest unit of processing that can be scheduled by the operating system.
- Main Thread: The initial thread that starts executing when a C++ program begins.
- Creating Threads: Threads can be created using the
std::threadclass. - Joining Threads: Threads can be synchronized using the
joinmethod to wait for them to complete.
Creating and Running Threads
Example: Basic Thread Creation
Let’s create a simple example where we launch a separate thread to perform a task.
#include <iostream>
#include <thread>
void printMessage(const std::string& message) {
std::cout << message << std::endl;
}
int main() {
// Create a thread
std::thread t(printMessage, "Hello from thread!");
// Wait for the thread to complete
t.join();
std::cout << "Hello from main!" << std::endl;
return 0;
}
Output
Hello from thread!
Hello from main!
Explanation
- The
printMessagefunction prints a message to the console. - A
std::threadobjecttis created, which starts executing theprintMessagefunction in a separate thread. - The
joinmethod is called to wait for the threadtto complete before continuing in themainfunction.
Passing Arguments to Threads
You can pass arguments to the thread function using the std::thread constructor.
Example: Passing Arguments
#include <iostream>
#include <thread>
void printSum(int a, int b) {
std::cout << "Sum: " << a + b << std::endl;
}
int main() {
int x = 5;
int y = 10;
// Create a thread
std::thread t(printSum, x, y);
// Wait for the thread to complete
t.join();
return 0;
}
Output
Sum: 15
Explanation
- The
printSumfunction takes two integers as arguments and prints their sum. - A
std::threadobjecttis created, which starts executing theprintSumfunction with the argumentsxandy. - The
joinmethod is called to wait for the threadtto complete before continuing in themainfunction.
Detaching Threads
Detaching a thread allows it to run independently from the main thread. The main thread will not wait for the detached thread to finish.
Example: Detaching a Thread
#include <iostream>
#include <thread>
void printMessage(const std::string& message) {
std::cout << message << std::endl;
}
int main() {
// Create and detach a thread
std::thread t(printMessage, "Hello from detached thread!");
t.detach();
std::cout << "Hello from main!" << std::endl;
// Allow time for the detached thread to finish
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
Output
Hello from main!
Hello from detached thread!
Explanation
- The
printMessagefunction prints a message to the console. - A
std::threadobjecttis created and detached, allowing it to run independently. - The
mainfunction usesstd::this_thread::sleep_forto wait for the detached thread to finish executing.
Synchronization
Synchronization is crucial in multithreading to avoid data races and ensure data integrity. C++ provides several synchronization mechanisms, such as mutexes and condition variables.
Example: Using Mutex for Synchronization
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void printMessage(const std::string& message) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << message << std::endl;
}
int main() {
std::thread t1(printMessage, "Hello from thread 1!");
std::thread t2(printMessage, "Hello from thread 2!");
t1.join();
t2.join();
return 0;
}
Output
Hello from thread 1!
Hello from thread 2!
Explanation
- The
std::mutexobjectmtxis used to synchronize access to the console. - The
printMessagefunction uses astd::lock_guardto lock the mutex while printing the message. - Two threads,
t1andt2, are created and joined, ensuring synchronized access to the console.
Practical Example: Multithreaded Calculation
Let’s create a more practical example where multiple threads calculate the sum of different parts of an array.
Code Example
#include <iostream>
#include <thread>
#include <vector>
void partialSum(const std::vector<int>& arr, int start, int end, int& result) {
result = 0;
for (int i = start; i < end; ++i) {
result += arr[i];
}
}
int main() {
std::vector<int> arr(100, 1); // Array with 100 elements, all set to 1
int result1 = 0, result2 = 0;
// Create two threads to calculate partial sums
std::thread t1(partialSum, std::ref(arr), 0, arr.size() / 2, std::ref(result1));
std::thread t2(partialSum, std::ref(arr), arr.size() / 2, arr.size(), std::ref(result2));
t1.join();
t2.join();
int totalSum = result1 + result2;
std::cout << "Total sum: " << totalSum << std::endl;
return 0;
}
Output
Total sum: 100
Explanation
- The
partialSumfunction calculates the sum of a portion of the array. - Two threads,
t1andt2, are created to calculate the sums of different parts of the array concurrently. - The
mainfunction waits for both threads to complete and then adds their results to get the total sum.
Conclusion
Multithreading in C++ allows you to run multiple threads concurrently, improving performance and responsiveness. The std::thread class provides a simple and effective way to create and manage threads. Synchronization mechanisms like mutexes ensure data integrity in multithreaded programs. Understanding and effectively using multithreading is essential for writing high-performance and reliable C++ programs.