Assignment Chef icon Assignment Chef
All English tutorials

Programming lesson

Parallel Merge Sort in C++: Boosting Data Sorting with Multi-Threading

Learn how to transform a sequential merge sort into a parallel version using C++ threads. This step-by-step tutorial covers thread creation, critical sections, and performance benchmarking with real-world data sizes.

parallel merge sort C++ multi-threaded sorting C++ sorting tutorial parallel data processing merge sort threads C++ std::thread benchmarking sorting algorithms critical section C++ thread ID vector C++ parallel programming sort large dataset C++ divide and conquer parallel C++ performance optimization merge sort parallel vs sequential C++ thread join sorting AI training data

Why Parallel Sorting Matters in 2026

In today's data-driven world, sorting large datasets efficiently is crucial. From ranking AI model outputs to ordering live sports stats during the NBA Finals, parallel processing is the key to speed. This tutorial builds on the classic merge sort algorithm, converting it into a multi-threaded C++ solution. You'll learn how to split data, distribute work across threads, and measure performance gains.

Understanding Merge Sort Basics

Merge sort is a divide-and-conquer algorithm. It splits an array into halves, recursively sorts each half, then merges the sorted halves. The sequential version is straightforward but slow for huge data sets because each recursive call runs on a single thread.

void merge_sort(int arr[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        merge_sort(arr, left, mid);
        merge_sort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }
}

The merge step combines two sorted subarrays into one. This is the part that can be parallelized: each recursive call can run on a separate thread.

Designing the Parallel Merge Sort

Your task is to create a function Parallel_Merge_Sort that splits the array into chunks and assigns each chunk to a thread. Each thread runs a sequential merge sort on its chunk. After all threads finish, you merge the sorted chunks sequentially.

Step 1: Determine Chunk Size

Divide the total number of elements by the number of threads. For example, with N = 100000 and 4 threads, each thread sorts 25000 elements.

Step 2: Create Threads

Use std::thread to launch sorting tasks. Store thread objects in a vector.

std::vector<std::thread> threads;
int chunk_size = N / num_threads;
for (int i = 0; i < num_threads; ++i) {
    int left = i * chunk_size;
    int right = (i == num_threads - 1) ? N - 1 : left + chunk_size - 1;
    threads.emplace_back(merge_sort_seq, arr, left, right);
}

Step 3: Join Threads

Wait for all threads to complete before merging.

for (auto& t : threads) t.join();

Step 4: Merge Sorted Chunks

After all threads finish, you have sorted chunks. Merge them pairwise (like a tournament bracket) to produce the final sorted array.

for (int step = chunk_size; step < N; step *= 2) {
    for (int left = 0; left < N; left += 2 * step) {
        int mid = left + step - 1;
        int right = std::min(left + 2 * step - 1, N - 1);
        if (mid < right) merge(arr, left, mid, right);
    }
}

Benchmarking Performance

To compare sequential vs. parallel, measure execution time using std::chrono. Start with a small N = 10 to verify correctness (print arrays), then increase to N = 100000 or more for timing.

auto start = std::chrono::high_resolution_clock::now();
merge_sort_seq(arr, 0, N - 1);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> seq_time = end - start;

Your parallel version should be faster. If not, check thread overhead: too many threads can slow things down. Aim for num_threads = std::thread::hardware_concurrency().

Adding a Global ID Vector

Modify your code to log thread IDs in a critical section. Declare a global std::vector<std::thread::id> and push the current thread's ID inside the merge function (or any shared resource access). Use a mutex to protect the vector.

std::vector<std::thread::id> thread_ids;
std::mutex mtx;

void merge(int arr[], int left, int mid, int right) {
    // ... merge logic ...
    {
        std::lock_guard<std::mutex> lock(mtx);
        thread_ids.push_back(std::this_thread::get_id());
    }
}

This helps visualize how many threads access the critical section.

Real-World Analogy: Sorting AI Training Data

Imagine you're preparing a massive dataset for training a large language model like GPT-5. Sorting millions of text samples by size or topic can be done in parallel, just like our merge sort. Each thread handles a batch, then the results are merged. This cuts processing time from hours to minutes.

Complete Code Structure

Your final program should:

  • Define const int N = 100000; for final testing.
  • Implement sequential merge sort for baseline.
  • Implement Parallel_Merge_Sort using threads.
  • Measure and display both times.
  • Show thread IDs from critical section.

Common Pitfalls

  • Race conditions: Ensure only one thread writes to shared data at a time.
  • Too many threads: More threads than cores can cause context switching overhead.
  • Not joining threads: Always join before accessing results.

Conclusion

Parallel merge sort is a practical introduction to multi-threaded programming in C++. By applying these techniques, you can speed up data processing tasks in any field—from finance to gaming leaderboards. Test your solution with different array sizes and thread counts to see the impact.