Table of Contents

  1. Introduction
  2. Understanding Multithreading in C++
  3. Fundamentals of Multithreading in C++
  4. Real-Time Example: Image Processing
  5. Conclusion

1 - Introduction

Multithreading, the concurrent execution of multiple threads within a single program, is a powerful technique that can significantly enhance the performance and responsiveness of applications. In this exploration, we'll delve into the world of multithreading in C++, understanding its fundamentals and witnessing its impact through a real-time example.

2 - Understanding Multithreading

Multithreading enables parallel execution of code by breaking it into smaller, independently executable threads. These threads can run concurrently, sharing the same resources but operating independently. In C++, multithreading is facilitated by the <thread> header and related classes.

Benefits of Multithreading

  • Improved Performance: Multithreading allows concurrent execution, leveraging the full potential of modern processors.
  • Responsiveness: Applications can remain responsive even when executing computationally intensive tasks.
  • Modularity: Code can be modularized into separate threads, enhancing maintainability.

3 - Fundamentals of Multithreading in C++

Thread Creation

In C++, creating a thread is as simple as instantiating an object of the std::thread class and passing the function to be executed concurrently.

#include <iostream>
#include <thread>

void myFunction() {
    // Code to be executed in the new thread
}

int main() {
    std::thread myThread(myFunction);  // Creating a new thread
    myThread.join();  // Ensuring the main thread waits for myThread to finish
    return 0;
}

Thread Synchronization

When multiple threads access shared data, synchronization becomes crucial to avoid data races and ensure consistency. C++ provides various synchronization mechanisms, such as mutexes (std::mutex), condition variables (std::condition_variable), and atomic operations (std::atomic).

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

std::mutex myMutex;

void sharedResourceAccess() {
    std::lock_guard<std::mutex> lock(myMutex);  // Locking the mutex
    // Code to access shared resource
}  // Mutex automatically released upon leaving the scope

int main() {
    std::thread thread1(sharedResourceAccess);
    std::thread thread2(sharedResourceAccess);
    thread1.join();
    thread2.join();
    return 0;
}

4 - Real-Time Example: Image Processing

Let's bring multithreading to life with a practical example: image processing. Consider a scenario where an application needs to apply different filters to an image concurrently for faster processing.

Problem Statement

We have an image represented as a matrix of pixels. We want to apply multiple filters (e.g., blur, sharpen) to the image simultaneously using multithreading.

Implementation

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

// Define image processing functions with mutex protection
void applyBlur(std::vector<std::vector<int>>& image, int startX, int endX, std::mutex& segmentMutex) {
  std::lock_guard<std::mutex> lock(segmentMutex);  // Lock the segment mutex
  std::cout << "startX="<< startX << " endX="<< endX <<" applyBlur" << std::endl;
  // Apply blur filter to the specified portion of the image
  // Code for blur filter
}

void applySharpen(std::vector<std::vector<int>>& image, int startX, int endX, std::mutex& segmentMutex) {
  std::lock_guard<std::mutex> lock(segmentMutex);  // Lock the segment mutex
  std::cout << "startX="<< startX << " endX="<< endX <<" applySharpen" << std::endl;
  // Apply sharpen filter to the specified portion of the image
  // Code for sharpen filter
}

int main() {
    // gray scale image 0 - black  256 - white
  std::vector<std::vector<int>> image= {
      {5,6,32,90},
      {6,34,2,100},
      {5,4,3,54},
      {67,34,23,56},
      {5,6,32,90},
      {6,34,2,100},
      {5,4,3,54},
      {67,34,23,56},
      {5,6,32,90},
      {6,34,2,100},
      {5,4,3,54},
      {67,34,23,56},
      {5,6,32,90},
      {6,34,2,100},
      {5,4,3,54},
      {67,34,23,56}
  };
  // Load the image matrix

  // Divide the image into segments for concurrent processing
  int segments = std::thread::hardware_concurrency();
  
  std::cout << segments << std::endl;
  
  int segmentSize = image.size() / segments;
  
  std::cout << segmentSize << std::endl;

  // Create separate mutexes for each image segment
  std::vector<std::mutex> segmentMutexes(segments);

  // Create threads for concurrent image processing, passing the relevant mutex
  std::vector<std::thread> threads;
  for (int i = 0; i < segments; ++i) {
      
    
    int startX = i * segmentSize;
    int endX = (i == segments - 1) ? image.size() : startX + segmentSize;
    std::cout << "i=" << i << " startX="<< startX << " endX="<< endX << std::endl;
    threads.emplace_back(applyBlur, std::ref(image), startX, endX, std::ref(segmentMutexes[i]));
    threads.emplace_back(applySharpen, std::ref(image), startX, endX, std::ref(segmentMutexes[i]));
  }

  // Join threads to wait for their completion
  for (auto& thread : threads) {
    thread.join();
  }

  // Display or save the processed image

  return 0;
}

Explanation

In this example, we simulate an image represented as a matrix of pixels. The image processing functions (applyBlur and applySharpen) are designed to work on specific segments of the image concurrently. We utilize multiple threads to apply these filters simultaneously, dividing the image into segments for parallel processing.

A mutex (myMutex) is employed to ensure thread safety when accessing shared resources, in this case, portions of the image matrix.

5 - Conclusion

Multithreading in C++ is a powerful paradigm that unlocks performance gains and responsiveness in applications. By understanding the fundamentals and witnessing a real-time example of image processing, developers can harness the potential of multithreading to optimize their software for concurrent execution. Whether it's for complex computations, concurrent I/O operations, or parallelizing tasks, multithreading in C++ empowers developers to build efficient and responsive applications.