
PCYNLITX MULTITHREADING
Cybernetic thread management technology
This page includes a breif introduction to the pcynlitx multithreading
THE THREAD CONTROL MECHANISM
In the classical C++ multithreading, the block status of the threads is changed when a particular condition occurs. In this classical approach, the block status of the threads change without recognizing the identity of the threads. However, instead, in pcynlitx multithreading, the threads are controlled by means of their id numbers which are given by the software developers to the threads. In other words, the threads are blocked using ID numbers which are given by the programmer to the threads on thread creation. Moreover, you can control the threads in therms of the names of the functions which are executed by the threads. This situation has been illustrated on the figure which is given on the right site of this section.
The Advantages of the pcynlitx thread control mechanishm
This new approach brings some advantages. For instance, you can block a specific thread ( the thread having particular ID number ) in a particular location. Meanwhile, you can determine the execution order of the threads in critical sections. Especially, in some cases, the threads must perform some dependent operations and this operations must be performed in a particular order. This property significantly improves the internal determinism of the multithreaded software. Beside this, the determination of the order of the messages which are used for inter-thread communication is very difficult task. This approach provides fixed order messaging between the threads.
Finally, the controlling the threads with particular ID numbers reduces the complexity of the multithreaded software development and this property also icreases logical understandability of the software. You can find the theoretical foundation of the apprach which is used in pcynlitx multithreading library on the research paper cited on the home page. In the following sections and on the documentations, the practical usage of the pcynlitx library and the properties of the classes of the pcynlitx multithreading library will be explained.
Typical block operation
void function( ){
mt.lock();
if(condition){
cv.wait();{
}
mt.unlock();
}
Pcynlitx block operation
void function( ){
syn.wait(1);
}
The comperation of the pcynlitx multithreading with the classical tools
Advantages
- A naturel protection mechanism agains to the ordering violations
- Abstraction and simplification on coding
- Construction a secure messaging channel is very simple. An unexperienced developer can easily perform a secure messaging between the threads over a channel and the messaging operations are performed in a fixed order ( Stable and predictable messaging )
- Advanced thread control ( the controllability of the threads improves significantly )
- Improvements on internal determinism and simplification on the testing process
Disadvantages
- Fixed number of thread creation ( The threads must be spawned from single point and the threads can not be spawned a new thread.
- Neglable performance reduction.
INTRODUCTION TO THE BASIC LIBRARY CLASSES
It has been already mentioned that the main philosopy of the pcynlitx project is simplification and abstraction on software development. Therefore, the classes which are the parts of the pcynlitx library act as abstraction layer between the software developer and the thread control operations. In pcynlitx multithreading library, there are three main classes which are used. The other classes are the variants of these classes. Basically, these classes are responsible from thread creation, control and messaging. These classes are named as “threads”, “synchronizer” and “channel” in pcynlitx library. In pcynlitx project, these classes are named as cybernetic control classes and their instances are named as cybernetic control objects. The control classes of the pcynlitx library are listed in below with pcynlitx namespace.
threads
This class is responsible from the thread creation and joinning.
synchronizer
This class is used for the thread synchronization. It blocks the threads and rescues the threads from the blockage.
channel
This class is used for the thread channel construction for inter thread communication
THREAD CREATION AND JOINNING
In multi thread programming, the first step must be explanation of the thread creation and joining. In pcynlitx applications, it has been already mentioned that threads class is used for thread creation and joining. The constructor list of the threads class is given in below.
The list of constructors for threads class
explicit threads(int t);
t: the number of the threads to be created on the process
template<typename M>
void threads(int t, channel<M> * ch);
t: the number of the threads to be created on the process
ch: a poiner to a channel class instance
template<typename T>
void threads(T * ptr, int t);
t: the number of the threads to be created on the process
T: the type of the objects in which threads are created on its member functions
template<typename T>
void threads(T * ptr, int t, channel<M> * ch);
t: the number of the threads to be created on the process
T: the type of the objects in which threads are created on its member functions
ch: a poiner to a channel class instance
Just like regular C++ multithread programming, the function pointers pointing to the functions which are executed are passed as a parameter to the create function. In addition, a synchronizer object must be passed as a referance object on the function definition. In fact, the there is an object member of the threads class in the type of synchronizer. Therefore, the thread class automatically passes its synchronizer object to the function to be executed. A very simple tread creation example is given in below.
Pcynlitx thread creation and joining
SAMPLE -1
#include <iostream>
#include <thread>
#include <pcynlitx>
using namespace pcynlitx;
void function(syncronizer & syn){ – – 4
syn.connect(“function”); – – 5
std::cout << “\n thread number:” <<
syn.number(); – – 6
}
int main ( ){
threads th(2); – – 1
for(int i=0;i<2;i++){
th.create(function,i); – – 2
}
for(int i=0;i<2;i++){
th.join(i); – – 7
}
return 0;
}
Now, let us take closer look to the example which is given above. On the code line which is numbered as ( 1 ) , an instace of the thread class is constructed with name ‘th’. Then, on the code line which numbered as (2), two different threads are created with create function. The member function of the threads class, which is named as “create” takes two arguments. The first argument is the address pointer of the function to be executed and the second parameter is the id number of the threads to be created.
On the code line which is numbered as (3), a synchronizer object is declerated as a pass by reference parameter on the parameter list of the thread function. In fact, the synchronizer object is a default parameter of the thread functions on the pcynlitx multithreading applications and an instance of a synchronizer object is a default member of each threads class instance and it automatically passed to the threads to be created. The synchronizer object governs the executions of the threads in pcynlitx multithreading applications.
However, the most critical code line of the above example is the code line which is numbered as (5) and on this code line, a call to the connect member function of the synchronizer object is performed. When the connect member function is called, it bloks every threads which is executed on the process and the id numbers which are given by the operating system to the threads are received and they match to the id numbers which are given by the software developer. By this way, the threads can be controlled directly by means of the id numbers given by the software developer. All of these operations are performed automatically on the inside of the threads classes member functions. Meanwhile, on the pcynlitx multithreading applications, a call to the synchronizer object’s connnect member function must be performed on the top of each thread function and this operation is mandatory ( this is the only way of ID number mach).
On the code line which is numbered as (6), the id number of the caller thread is obtained by the member function which is named as “number”. It must be indicated that the id numbers which are given by the operating system is already matched on the previous code line numbered as (5) and therefore, on this code line, the id number given by the developer is obtained. The id numbers which are set on the thread creation.
THREAD SYNCHRONIZATION
In pcynlitx multithreading applications, the instances of the threads class has a default synchronizer object member and the flow of the threads are synchronized by this default instance of the synchronizer object. The synchronizer instances of the synchronizer objects can receive feedback from the process and the threads. Therefore, the in pcynlitx multithreading applications, the instances of the synchronizer object is named as cybernetic objects and they manipulates the thread flows cybernetically. In the below sections, pcynlitx thread control functions have been illustrated with simple examples.
BLOCKING THE THREADS WITH ID NUMBERS
In pcynlitx applications, the threads can directly be controlled by it id numbers. A simple coding sample is given below.
SAMPLE -2
#include <iostream>
#include <thread>
#include <pcynlitx>
using namespace pcynlitx;
void function(syncronizer & syn){
syn.connect(“function”);
syn.stop(2,1); – – 1
std::cout << “\n Thread Number:” << syn.number(); – – 2
syn.run(2,1); – – 3
}
int main ( ){
threads th(2);
for(int i=0;i<2;i++){
th.create(function,i);
}
for(int i=0;i<2;i++){
th.join(i);
}
return 0;
}
The output of the code is given below.
The output
Thread Number: 1
Thread Number: 2
SAMPLE-2 Explanation:
In this section, the thread which is numbered as 1 will be named as “thread-1” and the thread which is numbered as 2 will be named as “thread -2”. In the code given in above, the thread-2 is blocked when it performs a call to the function “stop(2,1)” and this code line is depicted with the line number -1.
void function(syncronizer & syn){
syn.connect(“function”);
syn.stop(2,1); ( thread -2 is blocked )
std::cout << “\n Thread Number:” << syn.number();
syn.run(2,1); ( thread -2 is activated by thread-1)
}
Then, the “thread-2” exits from the blocked stated when the “thread-1” performs a call to the member function “run(2,1)”. On the contrary, if the “thread-1” performs a call to member function “run(2,1)” before the “thread-2” performed a call to the member function “stop(2,1)”, then, the thread-1 waits at the member function “run(2,1)” until the “thread-2” perform a call to the member function “stop(2,1)”.
void function(syncronizer & syn){
syn.connect(“function”);
syn.stop(2,1);
std::cout << “\n Thread Number:” << syn.number();
syn.run(2,1);
/* if thread -1 reaches that point before thread-2 reached the stop function,
then thread-1 wait at that point. */
}
In breif, the “thread-1” always executes the section between the stop and run member functions before the “thread-2”. With the help of this property, the code section between the control function is executed in an exactly same order in each running of the software.
void function(syncronizer & syn){
syn.connect(“function”);
syn.stop(1);
}
In addition, you can block the threads with a particular id number.
BLOCKING THE THREADS IN THERMS OF ITS FUNCTION
In pcynlitx multithreading applications, the threads can be blocked in therms of the name of the function which is executed. The function prototypes and typical examples is given below.
Function prototypes
void stop(std::string Function_Name);
void stop(std::string Function_Name, int id);
SAMPLE -3
#include <iostream>
#include <thread>
#include <pcynlitx>
using namespace pcynlitx;
void procedures(syncronizer & syn){
syn.connect(“procedures”);
syn.stop(“procedures”);
// thread-1 and thread-2 cross the function together
/* Every threads which executes the function named
as procedures function is stopped */
/* When each thread which executes the function named
as procedures reach the same point every thread
start execution again */
syn.stop(“procedures”,3);
/* thread-1 and thread-2 waits until thread-3 performs a call
to the run(“procedures”,3) */
}
void activator_function(syncronizer & syn){
syn.connect(“activator_function”);
std::cout << “\n In order to complate thread executions, press enter”;
std::cin.get();
syn.run(“procedures”,3);
}
int main ( ){
threads th(3);
for(int i=0;i<2;i++){
th.create(procedures,i);
}
th.create(activator_function,3);
for(int i=0;i<3;i++){
th.join(i);
}
return 0;
}
SAMPLE-3: Explanation
In the example code that is given above, each thread which executes the function named as “procedures” wil be blocked untill the control function stop(“procedures”) is called by every thread executing the same thread function. In other words, the threads cross the code line together. On the other hand, the threads executing the function which is named as procedures are blocked egain when the threads perform a call to the control function stop(“procedures”,3). However, the threads wait an activation command coming from another thread executing a different function. The thread which is numbered 3 activates the other threads from another thread function.
You can get the name of the function to be executed.
void procedures(syncronizer & syn){
syn.connect(“procedures”);
std::cout << “\n The name of the function to be executed.”;
<< syn.function_name();
}
THE SERIAL EXECUTION OF THE CODE SECTION ( CRITICAL SECTIONS )
In pcynlitx multithreading applications, the code section can be executed serially. Different from the classical mutual exclution, the code section is executed in an exactly same order in each running of the software. More specifically, in each running of the software, the code sections are executed in an increasing order of the threads { 1, 2 , 3 , 4 . . . . . . }. This propertiy significaly reduces the ordering violations.
Ordering violations in multithreading
When the scheduling of the critical section is fixed, the bugs which are caused by random scheduling of the critical section are eliminated. In addition, the understandability of the source code improves significantly. Beside this, fixing the scheduling of the critical sections provides more successful testing and debugging. Moreover, this approach provides a natural protection mechanism against to the ordering violations which are faced on the multithreaded software systems. The ordering violations occurwhen execution order of the particular code sections is crucial and this order is not preserved on the runtime. A simple example for an ordering violation has been demonstrated in below code section.
void Function_1( ){
thread[2] = std::thread(Function_3); – – 1
}
void Function_2( ){
std::cout << “\n thread[2] id:” << << thread[2].get_id();
– – 2
}
In this particular example, the section-1 must be executed before section-2
Function prototypes
void start_serial( );
void end_serial( );
The serail executions of the code sections
void procedures(syncronizer & syn){
syn.connect(“procedures”);
syn.start_serial();
// The code section to be executed serially
syn.end_serial();
}
THE USAGE OF PCYNLITX MULTITHREADING INSIDE CLASS MEMBER FUNCTIONS
The constructor of the threads class differes from the classical constructor when the it is used in class member functions. The function prototypes of the threads class have been given in previous sections. However, the constructors which are used in class is given below.
Function Prototypes for the constructors ( in class usage )
template<typename T>
void threads(T * ptr, int t);
t: the number of the threads to be created on the process
T: the type of the objects in which threads are created on its member functions
template<typename T>
void threads(T * ptr, int t, channel<M> * ch);
t: the number of the threads to be created on the process
T: the type of the objects in which threads are created on its member functions
ch: a poiner to a channel class instance
SAMPLE -4
Class Decleration
class Test {
public:
Test(){ }
void Print(synchronizer & syn );
void RunThreads( );
}
Class Implementation
void Test::Print(synchronizer & syn ){
syn.connect(“Print”);
std::cout << “\n thread number:” << syn.number();
}
void Test::RunThreads( ){
threads<Test> th(this,4);
for(int i=0;i<4;i++){
th.create(Test::Print,i);
}
for(int i=0;i<4;i++){
th.join(i);
}
}
SECURE MESSAGING BETWEEN THE THREADS OVER A CHANNEL
In pcynlitx applications, you can send any information between the threads over a channel object. Channel class works based on a last in first out queue class. A typical example for channel class usage has been given in below.
SAMPLE -5
Class Decleration
class Test {
public:
Test(){ }
void PrintMessage(synchronizer_channel<std::string> & syn );
void RunThreads( );
}
Class Implementation
void Test::PrintMessage(synchronizer_channel<std::string> & syn ){
syn.connect(“Print”);
std::cout << “\n thread number:” << syn.number();
syn.stop(3,1); // The thread 3 always executed after thread-1
if(syn.number() == 0){
std::string s = “Hello”;
syn << s;
}
syn.run(3,1); // The thread-3 starts execution after thread-1 calls syn.run(3,1)
if(syn.number() == 3){
std::string s;
syn >> s;
std::cout << “\n The message coming:” << s;
}
}
void Test::RunThreads( ){
channel<std::string> ch;
ch.set_producer(0);
ch.set_consumer(3);
threads<Test> th(this,4);
for(int i=0;i<4;i++){
th.create(Test::PrintMessage,i);
}
for(int i=0;i<4;i++){
th.join(i);
}
}
In this particular sample code, thread-3 always stops when it performs a call to the function “syn.stop(3,1)” and it waits the activation signal coming from the thread-1. Therefore, in each running of the software, thread-1 sets the information to the channel before a reading operation performing by the thread-3.
Pcynlitx Software Systems
ABOUT
The pcynlitx project is carried out by Erkam Murat Bozkurt who is control systems engineer with M.Sc degree.
PRODUCTS
Pcynlitx IDE
Pcynlitx Multithreading Library
RESEARCH
The main purpose of the researches performed on pcynlitx project is to simplifiy software development with C++
LICIENCE
The software are distributed with apache software liciense
CONTACT
pcynlitx.help@gmail.com
erkam@pcynlitx.com
The source codes that are distributed on pcynlitx projects are copyrited on U.S copyright office. Copyright © 2025. All rights reserved.