Practical C++ Multithreading Programming

Practical C++ Multithreading Programming

Introduction

C++ is a powerful programming language that excels not only in system-level programming and game development but also supports multithreading. Multithreading can improve the responsiveness and processing capability of programs, allowing them to execute multiple tasks simultaneously. In this tutorial, we will delve into multithreading programming in C++, including how to use the standard library’s <span><thread></span> header file to create and manage threads.

1. Basics of Multithreading

Before understanding how to build multithreaded applications in C++, it is essential to grasp some basic concepts:

  • Process: The basic unit of resource allocation in an operating system. Each process has its own address space, memory, and executable code.
  • Thread: An execution path within a process, where multiple threads of the same process share the resources of that process (such as memory).

Through multithreading, we can utilize the CPU resources of a computer more efficiently.

2. Creating Simple Threads

In C++11 and later versions, the standard library provides the <span>std::thread</span> class, which makes it easy to create new threads. Below is a simple example demonstrating how to create and start a new thread.

Example Code:

#include <iostream>
#include <thread>
void say_hello() {    std::cout << "Hello from thread!" << std::endl;}
int main() {    // Create a new thread and point to the say_hello function    std::thread t(say_hello);
    // Wait for thread t to finish    t.join();
    std::cout << "Thread has finished execution." << std::endl;
    return 0;
}

Code Explanation:

  1. Include <span><iostream></span> for input-output streams, and <span><thread></span> for multithreading.
  2. Define the <span>say_hello</span> function, which will be executed in the thread.
  3. In the <span>main()</span> function, create a new <span>std::thread</span> object named <span>t</span> and pass the function to be executed in the thread, <span>say_hello</span>.
  4. Use <span>t.join()</span> to wait for the newly created thread to finish, blocking the main program until the child thread completes.

3. Passing Data Between Threads

Sometimes we need to pass data between threads. This can be achieved through parameters. This is done by modifying the constructor:

Example Code:

#include <iostream>
#include <thread>
void print_number(int num) {    std::cout << "Number: " << num << std::endl;}
int main() {    int number = 42;
    // Create a new thread and pass the number parameter to the print_number function     std::thread t(print_number, number);
    t.join();
    return 0;
}

Code Explanation:

  1. Define the <span>print_number(int num)</span> function, which takes an integer parameter and prints it.
  2. In the <span>main()</span> function, pass the value of the variable <span>number = 42</span> as a parameter to the newly created thread <span>t</span>.

4. Protecting Shared Data with Mutexes

When multiple threads access the same memory area, race conditions may occur. Therefore, we need to use a mutex to protect shared data. The standard library provides a mutex class through <span><mutex></span>.

Example Code:

#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // Declare a mutex
int shared_data = 0; 
void increment() {   for (int i = 0; i < 10000; ++i) {       mtx.lock();             // Lock        ++shared_data;         // Modify shared data        mtx.unlock();           // Unlock    }}
int main() {   std::thread t1(increment);   std::thread t2(increment);
   t1.join();   t2.join();
   std::cout << "Final value of shared_data: " << shared_data << std::endl;
   return 0;
}

Code Explanation:

  1. Declare a global integer variable <span>shared_data</span> for sharing between the two threads.
  2. Use <span>mtx.lock()</span> and <span>mtx.unlock()</span> to protect safe access to this variable. Both threads call <span>increment()</span>, iterating 10,000 times to increase the shared data.

Conclusion

This article introduced the basic knowledge of multithreading in C++, from simple examples to handling shared data using mutexes. It not only demonstrated the general structure of multithreading capabilities in C++ but also discussed how to safely handle shared data. We hope this helps you better understand and practice C++ multithreading programming techniques!

For further learning, it is recommended to explore more advanced features such as condition variables and deadlock prevention strategies through relevant literature or resources to enhance your understanding.

Leave a Comment