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::thread
class. - Joining Threads: Threads can be synchronized using the
join
method 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
printMessage
function prints a message to the console. - A
std::thread
objectt
is created, which starts executing theprintMessage
function in a separate thread. - The
join
method is called to wait for the threadt
to complete before continuing in themain
function.
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
printSum
function takes two integers as arguments and prints their sum. - A
std::thread
objectt
is created, which starts executing theprintSum
function with the argumentsx
andy
. - The
join
method is called to wait for the threadt
to complete before continuing in themain
function.
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
printMessage
function prints a message to the console. - A
std::thread
objectt
is created and detached, allowing it to run independently. - The
main
function usesstd::this_thread::sleep_for
to 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::mutex
objectmtx
is used to synchronize access to the console. - The
printMessage
function uses astd::lock_guard
to lock the mutex while printing the message. - Two threads,
t1
andt2
, 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
partialSum
function calculates the sum of a portion of the array. - Two threads,
t1
andt2
, are created to calculate the sums of different parts of the array concurrently. - The
main
function 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.