Beginner’s Guide to Multithreading in C++ with std::thread

Multithreading in C++

Welcome to Rambod.net! Today, we’re diving into multithreading in C++ using the powerful and intuitive std::thread. Multithreading allows you to execute multiple tasks simultaneously, making your applications faster and more responsive. Whether you’re building a game engine, a data processor, or a GUI application, multithreading can drastically improve performance.

In this article, we’ll explore the basics of std::thread, how to use it effectively, and provide 5 practical examples to get you started. Let’s make multithreading easy!


What is std::thread in C++?

std::thread is part of the C++11 standard, providing a clean and cross-platform way to create and manage threads. It enables you to run code concurrently without the need for third-party libraries or platform-specific APIs.

Why Use std::thread?

  • Concurrency: Perform tasks in parallel, reducing execution time.
  • Responsiveness: Avoid UI freezes by delegating heavy tasks to a separate thread.
  • Cross-Platform: Works on Windows, Linux, and macOS without modification.

Getting Started with std::thread

To use std::thread, include the <thread> header. A thread can execute any function, lambda, or callable object. Let’s look at some examples.


Example 1: Basic Multithreading with a Function

#include <iostream>
#include <thread>

void print_message(const std::string& message, int count) {
    for (int i = 0; i < count; ++i) {
        std::cout << message << " (iteration " << i + 1 << ")
";
    }
}

int main() {
    // Create a thread to execute the function
    std::thread t1(print_message, "Hello from thread!", 5);

    // Wait for the thread to finish
    t1.join();

    std::cout << "Main thread completed.
";
    return 0;
}

Output:

Hello from thread! (iteration 1)
Hello from thread! (iteration 2)
...
Main thread completed.

Example 2: Using Lambdas for Short Tasks

You can pass a lambda function directly to std::thread:

#include <iostream>
#include <thread>

int main() {
    std::thread t1([]() {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Lambda thread iteration " << i + 1 << "\n";
        }
    });

    t1.join();
    std::cout << "Main thread completed.\n";
    return 0;
}

Key Takeaway: Lambdas are perfect for short or one-off tasks.


Example 3: Detaching a Thread for Independent Execution

Detached threads run independently and don’t block the main thread. Be cautious, though, as accessing shared data requires synchronization.

#include <iostream>
#include <thread>
#include <chrono>

void long_task() {
    std::cout << "Starting a long task...\n";
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "Long task completed.\n";
}

int main() {
    std::thread t1(long_task);

    // Detach the thread
    t1.detach();

    std::cout << "Main thread is free to continue.\n";
    std::this_thread::sleep_for(std::chrono::seconds(1)); // Prevent program from exiting immediately
    return 0;
}

Output:

Starting a long task...
Main thread is free to continue.
(Long task completes in the background)

Example 4: Synchronizing Threads with std::mutex

When threads share data, use std::mutex to prevent race conditions.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void increment(int& counter) {
    for (int i = 0; i < 100; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        ++counter;
    }
}

int main() {
    int counter = 0;

    std::thread t1(increment, std::ref(counter));
    std::thread t2(increment, std::ref(counter));

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter << "\n";
    return 0;
}

Output:

Final counter value: 200

Example 5: Running Multiple Threads

Launch multiple threads to execute tasks in parallel:

#include <iostream>
#include <thread>
#include <vector>

void worker(int id) {
    std::cout << "Thread " << id << " started.\n";
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread " << id << " completed.\n";
}

int main() {
    const int num_threads = 4;
    std::vector<std::thread> threads;

    // Launch multiple threads
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(worker, i + 1);
    }

    // Wait for all threads to finish
    for (auto& t : threads) {
        t.join();
    }

    std::cout << "All threads completed.\n";
    return 0;
}

Output:

Thread 1 started.
Thread 2 started.
Thread 3 started.
Thread 4 started.
...
All threads completed.

Key Tips for Using std::thread

  1. Always join or detach: Ensure every thread is properly managed. Unjoined threads will cause program termination.
  2. Avoid Race Conditions: Use synchronization tools like std::mutex or std::lock_guard for shared data.
  3. Minimize Detached Threads: Detached threads are hard to manage and debug; prefer join unless truly necessary.
  4. Use std::atomic: For simple counters or flags, std::atomic avoids the overhead of mutexes.
  5. Prefer Modern C++ Features: Use lambdas, std::future, or thread pools for clean and maintainable code.
Multithreading in C++

Why Use std::thread in C++?

  • Simplicity: Create threads with minimal boilerplate.
  • Performance: C++ threads are highly efficient, with low overhead.
  • Portability: Code runs on any platform supporting the C++11 standard or later.

Further Reading

  1. C++ Multithreading Documentation
  2. Effective Multithreading in C++
  3. Concurrency in Action (Book)
  4. Understanding Race Conditions
  5. Intro to std::mutex
  6. Understanding Global Variables and Namespaces in C++ | Best Practices and Performance

Conclusion

Congratulations! You’ve just learned how to harness the power of std::thread in C++. From creating threads to synchronizing them with std::mutex, multithreading can now be part of your programming toolkit. With its simplicity and cross-platform nature, std::thread makes C++ multithreading both powerful and approachable.

Have questions or want to share your experiences? Leave a comment below or check out more tutorials on Rambod.net! 🚀

Recommended Posts

No comment yet, add your voice below!


Add a Comment

Your email address will not be published. Required fields are marked *

nineteen − two =