The Parallel Programming Library (PPL) is one of my favorite features in C++Builder runtime library. PPL allows developers to create tasks that run in parallel to take advantage of multi-core processors.
Using the PPL, you can: 1) speed up loops with a Parallel For, 2) run multiple tasks in parallel using TTask, and 3) use Future Objects to allow a process run with your program focused on other work until the future value is set.
To showcase the TTask feature of the PPL, I’ve created a C++Builder VCL application (build and tested using the C++Builder 10.4 Sydney release) that runs three sort algorithms in separate tasks – Bubble Sort, Shell Sort and the ISO C++ standard Sort (which implements the Quicksort algorithm).
The User Interface
The VCL user interface for my application includes a TButton, two TMemos, and four TLabels. The TButton onClick event handler creates a vector of integers, creates three TTasks (for the sort algorithms) and waits for the sort tasks to complete using the TTask::WaitForAll method.
The Code
MainUnit.h:
#ifndef MainUnitH #define MainUnitH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> #include <Vcl.ExtCtrls.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TButton *Button1; TLabel *SortingStatusLabel; TLabel *BubbleSortLabel; TMemo *Data_Memo; TMemo *SortResult_Memo; TLabel *ShellSortLabel; TLabel *STDSortLabel; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif
MainUnit.cpp:
//--------------------------------------------------------------------------- #include <vcl.h> #include <System.Threading.hpp> #include <vector> #include <algorithm> #pragma hdrstop #include "MainUnit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { _di_ITask My_Tasks[3]; const int max_data = 15000; // number of random numbers to create int LoopValue = 0; Button1->Enabled = false; Button1->Update(); BubbleSortLabel->Caption = "Bubble Sort"; BubbleSortLabel->Update(); ShellSortLabel->Caption = "Shell Sort"; ShellSortLabel->Update(); STDSortLabel->Caption = "std::sort"; STDSortLabel->Update(); SortingStatusLabel->Caption = "Sorting "+IntToStr(max_data)+" integers!"; SortingStatusLabel->Update(); // Windows GetTicks() start and stop for each sort method int StartBubble,StopBubble; int StartShell,StopShell; int StartSTD,StopSTD; Data_Memo->Lines->Clear(); SortResult_Memo->Lines->Clear(); // create a vector of data that all sort algorithms will use std::vector<int> my_data; // populate the vector with integers for (int i = 1; i <= max_data; i++) { int random_value = Random(max_data); my_data.push_back(random_value); // Data_Memo->Lines->Add(IntToStr(random_value)); } // copy data vector to sort vectors std::vector<int> bubble_data = my_data; std::vector<int> shell_data = my_data; std::vector<int> std_data = my_data; // First Task - Bubble Sort My_Tasks[0] = TTask::Create([&](){ // Set Bubble Sort Windows GetTickCount() StartBubble = GetTickCount(); // body of Bubble Sort bool swapp = true; while(swapp){ swapp = false; for (size_t i = 0; i < bubble_data.size()-1; i++) { if (bubble_data[i]>bubble_data[i+1] ){ bubble_data[i] += bubble_data[i+1]; bubble_data[i+1] = bubble_data[i] - bubble_data[i+1]; bubble_data[i] -=bubble_data[i+1]; swapp = true; } } } // Set the Bubble Sort Stop GetTicks() StopBubble = GetTickCount(); }); // Start the Bubble Sort Task My_Tasks[0]->Start(); // Second Task - Shell Sort My_Tasks[1] = TTask::Create([&](){ // Set Shell Sort Windows GetTickCount() StartShell = GetTickCount(); // body of the Shell Sort for (int gapSize = shell_data.size() / 2; gapSize > 0; gapSize /= 2) { for (int currentIndex = gapSize; currentIndex < shell_data.size(); currentIndex++) { // save the currentIndex int currentIndexCopy = currentIndex; // save the value of the currentIndex int item = shell_data[currentIndex]; while (currentIndexCopy >= gapSize && shell_data[currentIndexCopy - gapSize] > item) { shell_data[currentIndexCopy] = shell_data[currentIndexCopy - gapSize]; currentIndexCopy -= gapSize; } shell_data[currentIndexCopy] = item; } } // Set the Shell Sort Stop GetTicks() StopShell = GetTickCount(); }); // Start the Shell Sort My_Tasks[1]->Start(); // Third Task - std::sort My_Tasks[2] = TTask::Create([&](){ // Set std::sort Windows GetTickCount() StartSTD = GetTickCount(); // Body of the std::sort std::sort(std_data.begin(),std_data.end()); // Set the std::sort Stop GetTicks() StopSTD = GetTickCount(); }); // Start the Shell Sort My_Tasks[2]->Start(); // wait until all of the sorting tasks complete TTask::WaitForAll(My_Tasks, sizeof(My_Tasks)/sizeof(My_Tasks[0])-1); SortingStatusLabel->Caption = "Sorting All done!"; BubbleSortLabel->Caption = "Bubble Sort Time: " + IntToStr(StopBubble - StartBubble) + " ms"; BubbleSortLabel->Update(); ShellSortLabel->Caption = "Shell Sort Time: " + IntToStr(StopShell - StartShell) + " ms"; ShellSortLabel->Update(); STDSortLabel->Caption = "std::sort: " + IntToStr(StopSTD - StartSTD) + " ms"; STDSortLabel->Update(); // if you want to see the sort results un-comment // one of the for loops and the sort result memo statement // for(int n : std_data) { // for(int n : bubble_data) { // for(int n : shell_data) { // SortResult_Memo->Lines->Add(IntToStr(n)); // } // clear the vectors my_data.clear(); bubble_data.clear(); shell_data.clear(); std_data.clear(); Button1->Enabled = true; } //---------------------------------------------------------------------------
The form after sorting 15,000 integers
References
PPL – Parallel Programming Library – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_the_Parallel_Programming_Library
Using TTask – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TTask_from_the_Parallel_Programming_Library
Using TParallel::For – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TParallel.For_from_the_Parallel_Programming_Library
Using TTask::IFuture – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TTask.IFuture_from_the_Parallel_Programming_Library
Algorithms Library – https://en.cppreference.com/w/cpp/algorithm
std::sort – https://en.cppreference.com/w/cpp/algorithm/sort
C++Builder Product Information
C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code
C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.