Friday, February 16, 2024

My C++ exploration - concurrency - async and future - driven by the Intrinsic Motivation...



My whole professional life in the world of software was driven by Intrinsic Motivation.

Intrinsic motivation is the act of doing something without any obvious external rewards. You do it because it's enjoyable and interesting, rather than because of an outside incentive or pressure to do it, such as a reward or deadline.

An example of intrinsic motivation for a software engineer would be deciphering a piece of a framework code because you enjoy doing it and have an interest in the matter or subject, rather than doing it because you have to prove a point to others or pass an exam.

Intrinsic motivation comes from within, while extrinsic motivation arises from outside. When you’re intrinsically motivated, you engage in an activity solely because you enjoy it and get personal satisfaction from it.

Let's come back to the nitty gritty of C++.

Here's my exploration of the C++ async method from the future header.

C++ async is a function template from the <future> header that helps you execute functions asynchronously, potentially in separate threads. It returns a std::future object that you can use to track the progress and retrieve the result of the asynchronous task.

Key Concepts:

Asynchronous Execution: async launches the provided function in a different thread (or using other mechanisms) without blocking the calling thread. This allows your program to continue doing other work while the asynchronous task is running.

std::future: The std::future object returned by async serves as a placeholder for the result of the asynchronous task. You can use methods like get(), wait(), valid(), and ready() to manage and access the result.

Common Use Cases:

Performing I/O-bound operations (e.g., network requests, file reading/writing) without blocking the main thread.

Source Code:

/*


* Callback.h


*


* Created on: 28-Dec-2023


* Author: ridit


*/


#ifndef CALLBACK_H_

#define CALLBACK_H_


class CallBack {


public:


virtual void onStartTask() = 0;


virtual void onFinishTask() = 0;


};


#endif /* CALLBACK_H_ */


/*

* Caller.h

*

* Created on: Feb 15, 2024

* Author: som

*/


#ifndef CALLER_H_

#define CALLER_H_


#include <iostream>

#include "Callee.h"


using namespace std;


//forward declaration

class Callee;


class Caller : public CallBack{


private:


Callee* callee;


public:


Caller(){


    callee = new Callee(this);


}


void doOwnTask(){


    cout<<"Main thread id = " <<this_thread::get_id()<<endl;


    for(int i = 0;i<10;i++){


cout<<"Caller is doing its own task in the main thread..."<<endl;


}


}


void delegateTaskToCallee(){


callee->doBackgroundTask();


}


virtual ~Caller(){


}


void onStartTask(){


cout<<"The background task is starting"<<endl;


}


void onFinishTask(){

cout<<"The background task is finished. Thank you, Callee, for taking my burden"<<endl;


}


};


#endif /* CALLER_H_ */




/*

* Callee.h

*

* Created on: Feb 15, 2024

* Author: som

*/


#ifndef CALLEE_H_

#define CALLEE_H_


#include <iostream>

#include <future>

#include "CallBack.h"


using namespace std;


class Callee {


private:

CallBack* cb;


public:


Callee(CallBack* cb){


this->cb = cb;


}


virtual ~Callee(){


}


static bool task(){


cout<<"Background thread id = " <<this_thread::get_id()<<endl;


for(int i = 0;i<10;i++){

    cout<<"Callee is doing the background task"<<endl;

}


return true;


}


void doBackgroundTask(){


this->cb->onStartTask();


future<bool> futureTask = async(launch::async, Callee::task);


if(futureTask.get() == true){

    this->cb->onFinishTask();

    }


}


};


#endif /* CALLEE_H_ */




//============================================================================

// Name : Callback.cpp

// Author : Som

// Version :

// Copyright : som-itsolutions

// Description : Hello World in C++, Ansi-style

//============================================================================


#include <iostream>


#include "CallBack.h"


#include "Caller.h"


#include "Callee.h"


using namespace std;


int main() {


Caller* caller = new Caller();


caller->doOwnTask();


caller->delegateTaskToCallee();



return 0;


}



You may like my other research study vis-a-vis how the

evenlistener pattern has been implemented in Android UI input

events.


Here we go...


Tuesday, February 13, 2024

Are we heading for a doomsday - HAARP - the earthquake weapon of USA...

 HAARP, which stands for High-frequency Active Auroral Research Program, is a research facility located in Gakona, Alaska. Its primary purpose is to study the ionosphere, the uppermost layer of Earth's atmosphere. The ionosphere is ionized by radiation from the Sun, and it plays an important role in radio communications and navigation.


HAARP uses a powerful radio transmitter to send beams of radio waves into the ionosphere. These beams can cause changes in the ionosphere, which can be studied by other instruments at the facility. This research helps scientists to understand how the ionosphere works and how it can be affected by natural and man-made phenomena.

Now the crux...

Conspiracy theories !!! Universe you decide...



Here's another video - technical



READ... READ...



Sunday, February 4, 2024

jthread in C++ 20 concurrency - a wrapper around std::thread...

jthread is a new entrant in C++ 20. It's a simple wrapper around std::thread which is based upon RAII objective - that is resource acquisition is resource initialization.

The j in the jthread stands for automatic joining.

This means that there is no need to call join on the newly created thread object - the program won't terminate abnormally.

When a jthread object goes out of scope or is otherwise destroyed, it automatically calls join() to ensure the thread completes before the object is destroyed. This prevents potential resource leaks or undefined behavior that could occur with std::thread.

The other aspect of jthread is the cooperative interruption.

We will discuss it in the next post.

Saturday, January 20, 2024

The Barrier in C++ 20 concurrency - the programmer in me is still thriving...

Enjoy my training video on the C++ barrier...



Suppose three workers prepare data at different speeds, but a computation must begin only after all workers are ready. How do we synchronize them?

std::barrier is the answer in C++.

The std::barrier class is a synchronization primitive introduced in C++20. It allows a set of threads to synchronize at a certain point in their execution. It is similar to the std::latch class, but it can be reused multiple times.

A std::barrier object is initialized with a count, which specifies the number of threads that must reach the barrier before any of them can proceed. When a thread reaches the barrier, it calls the wait() method. If the count is not yet zero, the thread will be blocked until the count reaches zero. Once the count reaches zero, all of the threads that are waiting on the barrier will be released and can proceed.

The std::barrier class can be used to implement a variety of synchronization patterns, such as producer-consumer queues, parallel algorithms, and race condition prevention.

Here's my application in which I used barrier to showcase how it can be used.

Class Student

#include <iostream>

#include <string>

#include <thread>

#include <barrier>

#include <chrono>

#include <vector>

#include <syncstream> // For thread-safe console output

#include <format> // For C++20 string formatting


class Student {

private:

std::string name;

int timeLapseBeforeStarting; // in milliseconds

int timeToFinish; // in milliseconds


public:

// Optimized constructor using std::move to avoid redundant copies

Student(std::string studentName, int lapse, int finish)

: name(std::move(studentName)),

timeLapseBeforeStarting(lapse),

timeToFinish(finish) {}


// Virtual destructor is fine if subclassing, but defaulted here

virtual ~Student() = default;


void task(std::barrier<>& b) {

// 1. Simulate varying arrival times

std::this_thread::sleep_for(std::chrono::milliseconds(timeLapseBeforeStarting));


// 2. Synchronize at the barrier

b.arrive_and_wait();


auto now = std::chrono::system_clock::now();


// Locate the current system timezone and convert UTC to local time

auto local_time = std::chrono::current_zone()->to_local(now);


// std::osyncstream guarantees this block of output won't interleave with other threads

std::osyncstream(std::cout)

<< name << " is Starting the task at "

<< std::format("{:%F %T}", local_time) << "\n";

// 4. Simulate performing the task

std::this_thread::sleep_for(std::chrono::milliseconds(timeToFinish));


std::osyncstream(std::cout) << name << " finished the task.\n";

}

};

// ==========================================

// Class classETC

// ==========================================

#include "Student.h"

class classETC {

public:

Student ridit {"Ridit", 1000, 2000};

Student ishan {"Ishan", 3000, 1000};

Student rajdeep {"Rajdeep", 900, 1500};


classETC() = default;

virtual ~classETC() = default;


// FIX: Returns a container of jthreads to main() to keep them alive

auto giveTaskToStudent(std::barrier<>& b) {

std::vector<std::jthread> workers;

workers.reserve(3);


// Emplace threads directly into the vector

workers.emplace_back(&Student::task, &this->ridit, std::ref(b));

workers.emplace_back(&Student::task, &this->ishan, std::ref(b));

workers.emplace_back(&Student::task, &this->rajdeep, std::ref(b));


return workers; // Named Return Value Optimization (NRVO) handles this cleanly

}

};

The Main method

// ==========================================

// Main Method

// ==========================================

#include "classETC.h"

int main() {

// Print C++ standard validation

std::cout << "C++ Version: ";

if (__cplusplus == 202101L) std::cout << "C++23\n";

else if (__cplusplus == 202002L) std::cout << "C++20\n";

else std::cout << "Other/Experimental (" << __cplusplus << ")\n";

std::cout << "-------------------------------------------\n";


std::barrier b(3);

classETC etc;


// FIX: Capturing the threads in main() preserves their lifetimes.

// They will execute concurrently and automatically join when main() ends.

auto threads = etc.giveTaskToStudent(b);


return 0;

}

The heart of the above concurrent program is

 b.arrive_and_wait();
  • arrive() decrements the participant count.

  • wait() blocks until the count reaches zero.

  • arrive_and_wait() combines both.

The Output:

C++ Version: C++20

-------------------------------------------

Ridit is Starting the task at 2026-06-26 00:19:59.803930207

Ishan is Starting the task at 2026-06-26 00:19:59.803930524

Rajdeep is Starting the task at 2026-06-26 00:19:59.803929510

Ishan finished the task.

Rajdeep finished the task.

Ridit finished the task.

Have a look at the time when the three different threads are starting - all of them start at the same time - 00:19:59 - why?

It's because of the barrier!!!

And for the inquisitive mind...

Why is there a mismatch in the starting time in the range of just a few microseconds?

A variation of 1 to 20 microseconds is incredibly tight and proves that our std::barrier system is doing its job perfectly. In a multi-threaded system running on top of a general-purpose operating system (like Linux/Ubuntu), achieving true 0.000000 synchronicity is physically impossible due to these hardware and scheduling realities. To get any closer, we would need a hard Real-Time Operating System (RTOS) with core pinning and disabled interrupts!

Enjoy...

Friday, January 12, 2024

National Youth Day - here's is a clarion call to the engineers of Bharat - wake up and embrace Sanskrit...

 


Nikola Tesla and Swami Vivekananda

Mr. Toby Grotz, President, Wireless Engineering

Swami Vivekananda, late in the year l895 wrote in a letter to an English friend, "Mr. Tesla thinks he can demonstrate mathematically that force and matter are reducible to potential energy. I am to go and see him next week to get this new mathematical demonstration. In that case, the Vedantic cosmology will be placed on the surest of foundations. I am working a good deal now on the cosmology and eschatology of the Vedanta. I clearly see their perfect union with modern science, and the elucidation of the one will be followed by that of the other." (Complete Works, Vol. V, Fifth Edition, 1347, p. 77).

Here Swamiji uses the terms force and matter for the Sanskrit terms Prana and Akasha. Tesla used the Sanskrit terms and apparently understood them as energy and mass. (In Swamiji's day, as in many dictionaries published in the first half of the present century, force and energy were not always clearly differentiated. Energy is a more proper translation of the Sanskrit term Prana.)

Tesla apparently failed in his effort to show the identity of mass and energy. Apparently, he understood that when speed increases, mass must decrease. He seems to have thought that mass might be "converted" to energy and vice versa, rather than that they were identical in some way, as is pointed out in Einstein's equations. At any rate, Swamiji seems to have sensed where the difficulty lay in joining the maps of European science and Advaita Vedanta and set Tesla to solve the problem. It is apparently in the hope that Tesla would succeed in this that Swamiji says "In that case, the Vedantic cosmology will be placed on the surest of foundations."

Unfortunately, Tesla failed and the solution did not come till ten years later, in a paper by Albert Einstein. But by then Swamiji was gone and the connecting of the maps was delayed.

Engineers of Bharat - don't spend your life as a wage slave.



Reclaim your true identity... 

Embrace #Sanskrit

Read... Read...



Here's why we must declare Sanskrit as the national language of Bharat...


Let's discard Unity in diversity and embrace Unity in Unison - let's all embrace Sanskrit...




Here's my wife Reema reciting her own poem on wisdom


Sunday, January 7, 2024

Latches in C++ 20 concurrency - just like the CountdownLatch of Java concurrency package...

Multithreaded programming is inherently difficult. One of the reasons is that we can't have control over how a thread will start and finish - in which order - it all depends upon the thread scheduling algorithm of the OS. This makes the reproduction of test cases difficult. Moreover, there are race conditions and deadlocks.

When I was teaching the Countdown latch - a thread synchronization technique used in the Java Concurrency package, there was none like that available in C++. I  am happy to see that the concept of latch is introduced in C++20.

So...

What is a Latch in C++?

  • A synchronization primitive was introduced in C++20.
  • It allows one or more threads to wait for a certain number of operations to complete before proceeding.
  • Acts like a countdown counter that blocks threads until it reaches zero.
Good to know that the C++ team is trying to catch up with Java...

Here we go...

My experimentation with C++ latches.




I taught my young son Ridit about the Java Countdown latch three years ago.

Good to see the C++ team is making the standard library more powerful day by day.

Here is the C++ source code of my experimentation.

The following C++ code needs C++20 to compile and execute.


/*

* Student.h

*

* Created on: Jan 7, 2024

* Author: som

*/


#ifndef STUDENT_H_

#define STUDENT_H_


#include <iostream>

#include <string>

#include <thread>

#include <latch>

#include <chrono>

#include <vector>

#include <syncstream> // For thread-safe console output

#include <format> // For C++20 string formatting



class Student {


private:

std::string name;

int timeToFinish;


public:

Student(std::string name, int finish)

: name(std::move(name)),

timeToFinish(finish) {}


virtual ~Student() = default;


void task(std::latch& l){


auto now = std::chrono::system_clock::now();


// Locate the current system timezone and convert UTC to local time

auto local_time = std::chrono::current_zone()->to_local(now);


std::osyncstream(std::cout)

<< name << " is Starting the task at "

<< std::format("{:%F %T}", local_time) << "\n";

// 4. Simulate performing the task

                std::this_thread::sleep_for(std::chrono::milliseconds(timeToFinish));


std::osyncstream(std::cout) << name << " finished the task.\n";


l.count_down();

}

};


#endif /* STUDENT_H_ */




/*

* classETC.h

*

* Created on: Jan 7, 2024

* Author: som

*/


#ifndef CLASSETC_H_

#define CLASSETC_H_


#include "Student.h"



class classETC {


public:

Student ridit {"Ridit", 1000};

Student ishan {"Ishan", 3000};

Student rajdeep {"Rajdeep", 900};


classETC() = default;


virtual ~classETC() = default;



auto giveTaskToStudent(std::latch& l){


std::vector<std::jthread> workers;

workers.reserve(3);


// Emplace threads directly into the vector

workers.emplace_back(&Student::task, &this->ridit, std::ref(l));

workers.emplace_back(&Student::task, &this->ishan, std::ref(l));

workers.emplace_back(&Student::task, &this->rajdeep, std::ref(l));


std::cout<<"Teacher is waiting for all the students to finish their task"<<std::endl;


l.wait();


std::cout<<"All students submitted their task... Teacher is leaving the class"<<std::endl;


return workers; // Named Return Value Optimization (NRVO) handles this cleanly


}

};


#endif /* CLASSETC_H_ */




Main:


// ==========================================

// Main Method

// ==========================================

#include "classETC.h"

int main() {

// Print C++ standard validation

std::cout << "C++ Version: ";

if (__cplusplus == 202101L) std::cout << "C++23\n";

else if (__cplusplus == 202002L) std::cout << "C++20\n";

else std::cout << "Other/Experimental (" << __cplusplus << ")\n";

std::cout << "-------------------------------------------\n";


std::latch l(3);

classETC etc;


// FIX: Capturing the threads in main() preserves their lifetimes.

// They will execute concurrently and automatically join when main() ends.

auto threads = etc.giveTaskToStudent(l);


return 0;

}


Explanation of the code:


Have a look at the Student class. Each student will do their work in a
background thread. As there are 3 students, the latch will be initiated
with 3.

After completing the task, a student will reduce the latch counter by 1.
So when all the students complete the task, the latch - on which
the main thread was blocked, will become zero, and it will unblock the
main thread.

The C++ latches work exactly the way the Java Countdown Latch
works.


For your reference, here's my son Ridit on Java CountdownLatch.


#Enjoy


Wednesday, December 6, 2023

Why I taught my son Design Pattern even before Data Structure...



Learning beyond information suggests a shift from merely acquiring facts or data to deeper engagement with understanding, wisdom, or insights. It encourages individuals to move past surface-level knowledge and embrace more profound reflection, critical thinking, and personal meaning-making. This approach can involve synthesizing information to develop new perspectives, fostering creativity, or applying knowledge to real-world contexts. It emphasizes an active, interpretive process of learning, where information is just the starting point, leading to transformative thinking and decision-making.

Software is beyond memorizing the syntax of a specific programming language - we must get a clear image of the big picture. Studying design patterns helps a software developer get the big picture - from a designer's perspective. Knowing the common design patterns enables us to understand how different parts of the software are related to each other. Not only this, but knowledge of design patterns helps to communicate with other developers in a more object-oriented way.

Let me give you an example.

You know callback mechanism, observer pattern, and event listener pattern - all do kind of the same work - notify some objects when a specific event occurs. However, without the knowledge of design patterns, we will simply try to understand this phenomenon from just a programmer's point of view - and definitely, we will miss the big picture behind writing such kinds of object-oriented code.

I remember, when I studied the command routing architecture of Visual C++/MFC source code, I tried to map it with the Gang of Four design patterns and found out that this architecture uses two common design patterns at the same time - Command pattern and Chain of responsibility pattern.

Studying design patterns helps to decipher object-oriented code more like a professional - and not like a novice programmer. 

It helps to figure out the source code not only from what and how's point of view, but also from Why's point of view. We can explain why a piece of code has been or should be written in a particular way.

Understanding the Why's is very essential for a software developer.

Let me tell you about my journey in NOKIA India in 2007 using Symbian S60 C++ framework.

There is a concept in Symbian called a two-phase constructor. I asked people about the Why's point of view. Nobody gave me the answer - everybody said this is the norm in Symbian. While breaking my head about this "why", I went to Japan and then realized the reason for such a two-phase constructor - to avoid the exception during constructor in case of low memory. Because in the earlier days of mobile phones, there was limited memory and moreover there were no template concepts in C++. Hence there was no smart pointer. This led me to study Boost pointer in Japan in 2008 and voila, in 2009 Boost library became a part of the standard C++ library.

In concisely, to get the big picture of any object-oriented code structure, it's important to know Design Patterns. It clarifies many questions - particularly why a piece of code should be written in a specific manner.

Here's the evolutionary journey of Ridit, my son and a young Computer Scientist of Bharat - vis-a-vis Design Pattern...

My bragging right - as a Guru of my son...

State Pattern in Java : 8 yrs old

State pattern in C++ : 11 yrs old

State pattern in Python : 12 yrs old



Let me clarify it with another example.

I told my son that most of the modern GUI toolkit take a cue from Composite Design Pattern to design their UI components hierarchy. 

So when we are planning to delve into the source code of FreeCAD, i will show him this piece of code to bolster my claim.

The following python code is an example how FreeCAD component hierarchy is made through the design principles of Composite Design Pattern.



import FreeCAD as App

# Create a new document
doc = App.newDocument()

# Create a composite container (e.g., Part::Compound or App::Part)
composite = doc.addObject("App::Part", "CompositePart")

# Create child objects
box = doc.addObject("Part::Box", "Box")
sphere = doc.addObject("Part::Sphere", "Sphere")

# Set positions for better visualization
box.Placement.Base = App.Vector(0, 0, 0)
sphere.Placement.Base = App.Vector(5, 0, 0)

# Add child objects to the composite container
composite.addObject(box)
composite.addObject(sphere)

# Recompute the document to reflect changes
doc.recompute()

print("Composite Part created with Box and Sphere as children.")

App::Part as Composite Container: 
The App::Part object is a container that can hold other FreeCAD objects. This makes it suitable for creating composite structures.

Adding Objects to Composite: 
The addObject method of App::Part allows associating child objects with the container.

Recompute: The doc.recompute() call updates the FreeCAD model to reflect changes in the document.

I must admit that parenting is one of the best phases of my life. I got a purpose behind my struggles in the software industry.

Jai Hind...