Sooner or later the subject of multi-tasking or multi-threading comes up when programming. We’ll try to answer some of the most common questions about multi-threading or multi-tasking in C++, because multi-tasking can be useful in the future when developing C++ applications with the C++ IDE.
- What is a task?
- What do we mean by multi-tasking?
- What is a thread?
- What is multi-threading?
- Why do we need the TTask class?
- Why do we need to use a thread?
- How to implement tasks
- How to implement a thread
- Differences between a task and a thread
- What are the differences between parallel programming and multi-tasking?
- Can we use multi-threading when drawing?
Table of Contents
Use the C++ Builder Parallel Programming Library for multi-tasking
The Parallel Programming Library (PPL) provides a TTask class to run one task or multiple tasks in parallel. A Task is a unit of work you need to get done. The PPL does the association between the task and the thread that performs the task so you can run several tasks in parallel without having to create your own custom threads and managing them.
There is thread-associated classes in System.Threading. The Thread is a small set of executable instructions. When the time comes when the application is required to perform few tasks at the same time.
Task is an object that represents some work that should be calculated by a thread. Tasks class to let you create tasks and run them asynchronously. The task can tell you if the work is completed and if the operation returns a result, the task gives you the result .can be used whenever you want to execute something in parallel. Asynchronous implementation is easy in a task, using’ async’ and ‘await’ keywords.
TTask creates and manages interaction with instances of ITask. ITask is an interface that provides a range of methods and properties to Start, Wait, Cancel and also a property for Status (Created, WaitingToRun, Running, Completed, WaitingForChildren, Canceled, Exception).
How can I prevent my program’s user interface from becoming unresponsive in C++?
One functionality of TTask is to prevent the user interface from locking up if you want to start something in the background. The following code example shows how to run a single task and start it:
What is the difference between a
Here are some differences between a task and a thread in C++
- The Thread class is used for creating and manipulating a thread in Windows. A Task represents some asynchronous operation and is part of the Task Parallel Library, a set of APIs for running tasks asynchronously and in parallel.
- The task can return a result. There is no direct mechanism to return the result from a thread.
- Task supports cancellation through the use of cancellation tokens. But Thread doesn’t.
- A task can have multiple processes happening at the same time. Threads can only have one task running at a time.
- We can easily implement Asynchronous using ’async’ and ‘await’ keywords.
- A new Thread()is not dealing with Thread pool thread, whereas Task does use thread pool thread.
- A Task is a higher level concept than Thread.
CLANG Enhanced Compilers
If we are using a Clang-enhanced C++ compiler, we can use lambda expressions:
1 2 3 4 5 6 |
_di_ITask task = TTask::Create([&]() { // do calculations here }); task->Start(); |
Using multi-threading for any C++ Compiler
For any C++ compiler, we can declare a TProc subclass and use an instance of it casted as _di_TProc
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class TCppTask : public TCppInterfacedObject<TProc> { public: void __fastcall Invoke() { // do calculations here } }; void __fastcall TForm1::Button1Click(TObject *Sender) { _di_ITask task = TTask::Create(_di_TProc(new TCppTask())); task->Start(); } |
We can start multiple tasks as below,
1 2 3 4 5 6 7 8 9 |
for(int i = 0; i < count; i++) { task[i] = TTask::Create([i, &totalPrimeCount, this]() { if(calculate(i)) TInterlocked::Increment(count); }); task[i]->Start(); } |
How to use multi-threading in bitmaps and/or in canvas,
TCanvas
and all subclasses have support for multi-threaded environments, but does not support simultaneous execution of Canvas instances. This means that when a Canvas calls BeginScene
, the execution of the code inside this BeginScene...EndScene
section blocks any other thread that attempts to process drawing, including drawing on other canvases.
Write BeginScene...EndScene
blocks as short as possible to avoid blocking other threads.
TBitmap
has complete multi-threading support. Instances can be created, destroyed, and modified in any thread without synchronization. It has also Canvas property that can be used to draw drawings into images with multi-threading.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
TCanvas *canvas = Bitmap1->Canvas; for(int i= 0; i<10000; i++) { // thread work canvas->BeginScene(); try { // drawing code } __finally { Canvas->EndScene(); } } |
Note: You will still require normal thread synchronization if you share objects between threads, to ensure an object is not deleted while another thread is using it. Also, be cautious adding your own synchronization around bitmap access. It can cause deadlocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
class calc_Thread : public TThread { private: protected: virtual void __fastcall Execute(); float calc_SORpart(); public: __fastcall calc_Thread(bool CreateSuspended); int workerno, work_start, work_end; }; //--------------------------------------------------------------------------- __fastcall calc_Thread::calc_Thread(bool CreateSuspended) : TThread(CreateSuspended) { this->OnTerminate= Form1->calc_ThreadTerminated; this->FreeOnTerminate= true; } //--------------------------------------------------------------------------- void __fastcall calc_Thread::Execute() { FreeOnTerminate=true; workers++; err=calc_SORpart( ); //Synchronize(); } //--------------------------------------------------------------------------- void __fastcall TForm1::calc_ThreadTerminated(TObject *Sender) { workers--; } //--------------------------------------------------------------------------- float calc_Thread::calc_SORpart( void) { float psolx,errx=0; for(int o=work_start; o<=work_end; o++) { psolx=sol[o]; sol[o] = (1.0-omega)*sol[o]+ omega*(x[o]-m[o].B*sol[m[o].b]-m[o].D*sol[m[o].d]-m[o].F*sol[m[o].f]-m[o].H*sol[m[o].h])/m[o].E; errx=max(errx,fabs( (sol[o]-psolx)/(sol[o]+epsi) )); z1+=pow(sol[o]-psolx,2.0); } return errx; } |
RAD Studio C++ Builder has everything you need to get programming with C++. Why not download a free trial today?