This project benchmarks the performance of different concurrency models in a Linux environment (WSL2). By implementing a parallel sorting algorithm (Bubble Sort + Merge Sort), the project evaluates the efficiency differences between Multi-Processing (using fork) and Multi-Threading (using std::thread).
The core objective is to analyze the overhead of Inter-Process Communication (IPC) via File I/O versus Shared Memory access, providing quantitative insights into system-level programming bottlenecks.
- Language: C++ (Standard Template Library)
- System API: Linux System Calls (
fork,waitpid) - Concurrency: C++11 Threading (
std::thread,std::mutex,std::ref) - Development Environment: Ubuntu 24.04 on WSL2 (Windows Subsystem for Linux)
- Compiler: GCC / Visual Studio Code
The project implements four distinct approaches to sort a large dataset of
- Algorithm: Standard Bubble Sort.
- Complexity: O(N^2).
- Purpose: Establishes a performance baseline. As N increases, execution time grows exponentially.
- Algorithm: Divides data into K chunks, sorts each sequentially, and merges them.
- Purpose: Demonstrates the efficiency of the "Divide and Conquer" strategy (K-Way Merge Sort).
- Mechanism: Uses
fork()to create K child processes. - IPC Method: File I/O. Child processes write sorted chunks to
.tmpfiles, and the parent process reads them for merging. - Bottleneck: High latency caused by disk read/write operations and context switching.
- Mechanism: Uses
std::threadto create K threads within a single process. - IPC Method: Shared Memory. Threads operate directly on the same memory space using references (
std::ref). - Advantage: Zero-copy overhead; significantly faster than Task 3.
Multi-Threading (Task 4) consistently outperformed Multi-Processing (Task 3).
- Reason: Task 3 relies on File I/O for Inter-Process Communication, which introduces significant disk latency. Task 4 utilizes Shared Memory, eliminating the need for data copying and I/O operations.
- Sweet Spot: For large datasets (N=1,000,000), increasing the number of partitions (K) to 32 significantly reduced execution time (e.g., Task 4 dropped to ~23s).
- Overhead Trade-off: When N is small (N=10,000), a large K (e.g., 32) actually degrades performance because the overhead of creating threads/processes outweighs the sorting benefits.
| N (Data Size) | K (Splits) | Task 3 (Process) | Task 4 (Thread) | Improvement |
|---|---|---|---|---|
| 1,000,000 | 4 | 33,239 ms | 37,203 ms | - |
| 1,000,000 | 12 | 6,778 ms | 6,366 ms | ~6% Faster |
| 1,000,000 | 32 | 2,441 ms | 2,344 ms | ~4% Faster |
(Note: Visualizations comparing execution times across different N and K values.)
Observation: As shown in the charts, Task 4 (Blue Line) maintains the lowest latency across most configurations, confirming the efficiency of the multi-threaded model.
(Figure: Performance comparison at K=12 splits. Task 4 shows superior performance )
Author: Wei Heng (M.S. Candidate in Biomedical Engineering, CYCU)
Focus: System Programming, Embedded Systems, Edge AI