
PCYNLITX MULTITHREADING
Cybernetic thread management technology
1. WHAT IS PCYNLITX MULTITHREADING LIBRARY
Basically, pcynlitx multithreading is a C++ template library providing thread control functions for multithreading applications. However, differently from the classical C++ multithreading applications, in pcynlitx library, the theoretical foundation of the software cybernetics is used. On the pcynlitx applications, the threads are managed by cybernetic control objects receiving feedback from both the operating system and the software developer. From the software developers perspective, pcynlitx library tries to minimize the complexity of the multithreaded software development and provides abstract software management tools.
2. DETERMINISIM ON THE MULTITHREADING
It is a well known fact that there are multiple program flows in multithreaded software and the behavior of the software may be unpredictable when the threads are running concurrently on the software. Because, the execution order of the threads is determined by the underlying hardware and/or the operating system and the software developer can not effect the schedulling of the threads.
In multithread computing, the execution order and the priority of the threads reflect the term of scheduling. More specifically, the scheduling is a decision about which thread will run and which thread will be suspended in a particular time interval. Therefore, the procedures and code sections on the multithreaded software applications are executed randomly and the execution order of the code sections are changed in each running of the threads. This situation has been illustrated in below image.

In the above figure, how the scheduling of the particular code segments effects internal determinism has been illustrated. The numbers that are given in the above figure represent the execution order of the code segments on the multi-thread programming applications. In Figure (a), a typical nondeterministic scheduling has been illustrated and the execution order of the code segments changes on each running of the software. However, in the Figure (b), deterministic scheduling of the threads has been illustrated and the execution order of the code segments is constant. In breif, random schedulling of the threads in multithreading leads nondeterminism and nondeterminism is the one of the reasons of the complexity that are faced on the multithreaded software applications.
2. 1 Fixing the execution order of the critical sections
Differently from the classical thread control, the software developer can fix the execution order of the critical sections wtih the help of the cybernetic thread control technology. Determination of the execution sequance of the code sections significantly improves internal determinism and This mechanism provides natural protection againt the ordering violations that are faced multithread software applications. In other words, fixing the execution order of the code sections improves internal determinizm and sipmlifies multithreaded software development.

In software systems, when the determinizm is a design requirement, generally input-output determinizm is taken into account and it reflects obtaining the same output for the same input in each running of the software. However, on the contrary, the internal determinism which reflects determinism of each code section plays crucial role on the input-output determinism and input-output determisim can not be achived without internal determisim. In the figure that is given on above, the code section is executed in an exactly same order by the threads in each running of the software. With the help of the control functions of the pcynlitx multithreading library, the execution order of the critical section can be easily achive. Off course, a similar staged computation can be performed with standart C++ library functions such as std::future-std::promise functions. However, the implementation of this mechanism is highly difficult for average software developer and it has its own drawbacks.
A coding example which performs a comparations of the classical C++ approach and the pcynlitx aproach is given on the following PDF document.
3. THE THREAD CONTROL MECHANISM IN PCYNLITX MULTITHREADING
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.stop(1);
}
The comperation of the pcynlitx multithreading with the classical tools
Advantages
- Abstraction and simplification on coding
- A naturel protection mechanism agains to the ordering violations
- 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.
3.1 A BRIEF INTRODUCTION TO THE CYBERNETIC THREAD MANAGEMENT
In order to simplify the explanation of the cybernetic thread management, the instance of the most upper level wrapper class ( pcynlitx::threads ) is named as cybernetic control object this section. This wrapper class includes the other classes which exist on pcynlitx multi-threading library as its member objects.
On the classical multi-threading, the program flows are changed when a particular condition is met. However, on the contrary, in cybernetic the cybernetic thread management system, the condition is received by the member function of the cybernetic control object and the cybernetic control object gives its decision based on current call to a control function and its previous knowledge about the process. More specifically, the cybernetic control object has a memory and it receives each thread’s block status and the cybernetic control objects blocks or notifies the threads according to the other threads situation. In fact, the cybernetic object has a kind of situation awareness. In the pcynlitx multi-threading, the control functions ( or the control points ) of the library are used in order to collect information about the process status. A very simplified version of a cybernetic thread control function is shown below.
void stop(int a, int b){
int caller_number = this->number();
if(caller_number == a ){
TDS[caller_number].block_status = true;
this->stop(caller_number);
TDS[caller_number].block_status = false;
}
}
TDS: The data structure holding thread related data.
In this control function, when the thread in which its id number is ‘a’ performs a call to the “stop(a,b)” , the thread “a” is blocked and its status is set as blocked on the data structure holding thread status information. Beside this, when the corresponding control function “run(a,b)” is called by the thread “b”, this information has been taken into account. If the thread which is numbered as “a” is already blocked condition when the “run(a,b)” is called, then the thread “a” is notified and starts its execution again. On the other case, the thread numbered as “b” wait inside the function call “run(a,b)” until the thread “b” performs a call to the “stop(a,b)”; In other words, in the cybernetic execution of the software, the cybernetic objects may not give permission for the execution of the procedures even though the related condition is met. An illustration of the cybernetic thread management technology has been given below.

4. INTRODUCTION TO THE BASIC PCYNLITX MULTITHREADING
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
In pcynlitx multithreading applications, the thread class is the upper-most level wrapper classes and its instances are the compositions of the other classes on the library. Therefore, the constructors of the thread class must be shown in below list. On the thread construction of the thread class instances, the total number of the thread to be created must be passed as a parameter to the constractor. Similarly, if the threads will be created on the inside of an object member, the address of the object must be passed as an argument to the constructor.
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
4.1 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.
Pcynlitx thread creation and joining
create function patern
template<class F, class… Args>
create(F && fn, int thread_number, std::string function_name, Args &&… args);
Function parameters on thread creation
fn : The first parameter is an adress pointer to the function to be executed.
thread_number: The second parameter is the id number of the thread to be created. This number is set by the software developer.
function_name: The name of the function in therms of std::string
args: the rest of the parameters are variadics and a parameter can be pass in any number and type
On pcynlitx multithreading, 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 and therefore, the thread class automatically passes its synchronizer object to the function to be executed.
On pcynlitx multithreading, The only thing which is mandatory in pcynlitx multithreading is decleration of the syncronizer object on the function to be executed. A very simple tread creation example is given in below.
void function(pcynlitx::synchronizer & syn, the rest of the parameters )
A very simple tread creation example is given in below.
SAMPLE -1
#include <iostream>
#include <thread>
#include <pcynlitx>
using namespace pcynlitx;
void function(syncronizer & syn){ – – 3
std::cout << “\n thread number:” <<
syn.number(); – – 4
}
int main ( ){
threads th(2); – – 1
for(int i=0;i<2;i++){
th.create(function,i,”function”); – – 2
}
for(int i=0;i<2;i++){
th.join(i); – – 5
}
return 0;
}
4.1.1 The construction of the pcynlitx threads class instance:
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’. However, the constructor takes the total number of the threads which will be executed on the process in terms of integer.
threads th(2);
4.1.2 The thread creation on pcynlitx multithreading:
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 three 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. In addition to these parameters, the name of the function to be executed must be pass as std::string to the create function. By this way, the id numbers of the threads and the name of the function to be executed are received in runtime.
th.create(function,i,”function”);
function: function pointer holding the address of the thread function
i: the id number of the thread that is set by developer
“function”: the name of the function in terms of std::string
4.1.2 Passing arguments to the thread function
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.
void function(syncronizer & syn)
syn: an instance of the synchronizer object which is passed automatically to thread function
void function(syncronizer & syn)
syn: an instance of the synchronizer object which is passed automatically to thread function
4.1.2 Joining the threads
On the code line which is numbered as (4), the id number of the caller thread is obtained by the member function which is named as “number”.
th.join(i);
i: the id number of the thread that is set by developer
4.2 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, in the 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.
4.2.1 BLOCKING THE THREADS WITH ID NUMBERS
In pcynlitx applications, the threads can directly be controlled by their id numbers given by the developer. A simple coding example is given below.
SAMPLE -2
#include <iostream>
#include <thread>
#include <pcynlitx>
using namespace pcynlitx;
void function(syncronizer & syn){
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,”function”);
}
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 is named as “thread-1” and the thread which is numbered as 2 is 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.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.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 by the thread-1 before the thread-2 in each running of the software. Therefore, the code lines in which placed between these control functions are executed in an exactly same order in each running of the software. This property increases internal determinism of the multithreaded applications.
void function(syncronizer & syn){
syn.stop(1);
}
void function(syncronizer & syn){
syn.run(1);
}
In addition, you can block the threads with a particular id number just as seen on the above function. Similarly, you can also start execution of a particular thread with its id numbers.
4.2.2 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.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){
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,”procedures”);
}
th.create(activator_function,3,”activator_function”);
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” is 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, there is another control function on the same code section which is written as stop(“procedures”,3). In this code line, the threads executing the function which is named as procedures are blocked again when the threads perform a call to the control function stop(“procedures”,3). However, in this case, differently from the other control function, 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){
std::cout << “\n The name of the function to be executed.”;
<< syn.function_name();
}
4.2.3 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
void Function_1( ){
thread[2] = std::thread(Function_3); – – 1
}
void Function_2( ){
std::cout << “\n thread[2] id:” << << thread[2].get_id();
– – 2
}
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.
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.start_serial();
// The code section to be executed serially
syn.end_serial();
}
4.2.4 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 ){
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);
}
}
4.2.5 SECURE MESSAGING BETWEEN THE THREADS OVER A CHANNEL
In pcynlitx applications, to accomplish message-sending concurrency, you can send any information between the threads over a channel object. the idea of message sending concurrecy is simple: “Do not communicate by sharing memory; instead, share memory by communicating.” However, in real multithreading applications, a new questions arises when threads are synchronized by meas of messages: which message arrives first!. The pcynlitx multithreading provides a solution to this problem with controlling the thread execution order. In pcynlitx applications, Channel class works based on a last in first out queue class. A typical example for channel class usage has been given in below.
In pcynlitx applications, 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 ){
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
emb.muratbozkurt@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.