8. HOW THE THREADS ARE SYNCHRONIZED IN PCYNLITX
8.1 The construction of the manager object and its clients
In the library construction, the pcynlitx produces an application specific thread synchronization class that knows how many thread will be activated, how many thread function will be used on the process and what will be the name of the thread functions. Not surprisingly, the source of this information is the descriptor file. In pcynlitx, as already mentioned, the name of the class that is used in order to synchronize the threads is "Thread_Manager". This class is generated based on application specific data collected from the descriptor file. Beside to this, the manager object, which is in fact an instance of the Thread_Manager class, also collects some thread specific data from its clients on run-time. In fact, on each thread function, there must be a client of the manager object. On the initialization of the clients of the manager object, the manager object receives not only the ID number of the thread but also the name of the thread function to be executed by the thread from its clients. In other words, the manager object learns which thread function is executed by which thread and records this information into an array of structure. As a result, before the synchronization tasks, the manager object knows exactly how many threads there are on the process, what the ID numbers of these threads are and which thread function is executed by which thread. In fact, the ID numbers of the threads are determined by the operating system on run-time. Therefore, in order to avoid some possible programming errors on the pcynlitx applications, it must be clearly understood that how the ID number of a thread is determined after the thread’s creation on run-time. Actually, the instantiation of the clients of the manager object is performed on the beginning of the thread function ( the first code line on the function routines ). Just after the thread’s creation, the threads call the constructors of the manager object’s clients and the clients of the manager object makes indirection to the manager object’s constructor at the same time. Then, all of the threads are blocked on inside of the manager object’s constructor ( the first line of the thread function routines ) until each thread’s data will be received by the manager object.
In the figure, each thread executes its own thread function. Beside to this, each thread is blocked on the beginning of the thread function routine until the data of each thread will be received. However, this interaction between the manager object and its clients continues to the end of the process. in order to update its global knowledge about the process, the manager object continues to collect data from the process such as the status of the threads ( blocking / non-blocking ) if the threads continue their execution. In other words, the manager object updates its data autonomously after each operation that is performed on the process. The manager object is also an inter-thread object and as in the case of the other inter-thread objects, manager object is passed to the other threads over the server object. Of course, the client of the "Thread_Manager" class is named as "TM_Client” ( TM is an abbreviation of the Thread_Manager ). However, to be able to synchronize the threads, manager object can be reachable from each thread. Therefore, on each thread function, an instance of the TM_Client is required. Different from the other client classes, the constructor of the TM_Client takes two arguments. Its first argument is the address of thread specific data structure. The second argument is the name of the function that is executed by the thread and its type is standard C++ string. A sample illustration about the initialization of manager object is shown in below.
In order to prevent synchronization errors, the clients of the manager object ( the instances of the TM_Client ) must be instantiated on top of each thread function. The Thread_Manager class includes many public member functions that can be used in synchronization tasks. Now, we can investigate the thread control functions that are provided by the pcynlitx platform.
8.2 The thread control functions
In the previous section, it has been indicated that the threads are controlled by means of the manager object member functions. However, different from the other multi-threading libraries, "Thread_Manager" class is an application-specific class and it has some public members that can block a certain thread by means of their unique number given by the programmer and/or their function routines which are executed by.
8.2.1 Exit member function
In pcynlitx applications, at the end of each thread function, the usage of the member function which is named as "Exit( )" is mandatory. It informs the compilation of the execution of the caller thread to the manager object.
8.2.2 Wait-rescue member functions with one parameter
With these member functions, you can block or rescue the threads by means of their unique numbers given by the programmer. When the thread specified on the argument performs a call to the wait(int number) member function, the caller thread is blocked. The same thread can be rescued by the corresponding rescue member function by means of some other thread.
A sample example for the usage of these member functions are given in below. In the figure, it can be easily seen that thread(0) waits before Code Block-1 until the thread (1) performs a call to the member function rescue(0) after execution of the Code Block-2. Therefore, the user of the pcynlitx can control the execution order of the threads.
8.2.3 Wait-rescue member functions with two parameters
These member functions take two integer parameters. When the thread specified on the first parameter performs a call to the function, the caller thread is blocked. The second parameter is used in order to indicate the thread which will rescue the thread waiting later on. The corresponding rescue member function takes exactly same parameters and when the thread specified on the second parameter performs a call to the corresponding rescue member function, the thread waiting rescues from blockage. These member functions are given in below.
Let we investigate a more complicated control problem and let we consider that there are four different code section which must be exacuted in an order by different threads. An illustration of this thread control problem has been given in below figure. Now, let we assume that these code sections are named as Code Block-1, Code Block -2, Code Block -3 and Code Block-4. Then, let we also assume that the execution order of these code blocks are Code Block-1, Code Block -2, Code Block-3 and Code Block -4. Then,let we forward our assumption one step further and let we assume that the code blokes are written on two different function routines and each function routines are executed by two different threads.
As you can see from the figure, the thread which is numbered with "0" ( the thread(0) ) executes the thread function named as "Function_1" and it is blocked when it performs a call to the function wait(0,2). Similarly, the thread (1) executes the same thread function and it is blocked when it performs a call to the function wait(1,3). Now, let we look at what is going on the other thread function. When the thread(2) performs a call to the function wait(2,3), it is blocked. However, for the thread numbered as "3" ( the thread (3) ) is not blocked in anywhere and thus, it continues its execution. Beside to this, in the figure, there is another control function which is shown as "Get_Thread_Number()". This control function returns the number of the caller thread. In the figure, the integer variable which is shown as "TN" is used in order to hold the number of the threads. By this way, the inside of the if conditions are only executed by the thread indicated on the condition. This means that the Code Block-1 can only be executed by the thread(3). Beside to this, because of the other threads are in block condition, at first Code Block-1 is executed. Then, when the thread(3) performs a call to the function rescue(1,3), the thread(1) rescues from the block condition and it starts its execution. Therefore, secondly, the Code Block-2 is executed. Then, when it performs a call to the function rescue(2,1) which is written on the other thread function, the thread (2) rescues from the block condition and it starts its execution and therefore, the Code Block-3 is executed. Finally, when the thread(2) performs a call to the function rescue(0,2), the thread(0) rescues from the block condition and it starts its execution and the Code Block-4 is executed.
This code example shows the power of the control tools that are used on the pcynlitx applications. The execution order and the priority of the threads reflect the term of scheduling. In the classical threading libraries, the scheduling of the threads are determined by the operating system and in each run of the process, the threads are scheduled differently. However, in pcynlitx applications, you can exactly control the execution order not only the threads but also particular code segments.
8.2.4 The blocking the threads executing a particular thread function
The pcynlitix provides unmatched control tools for thread synchronization. The one of them is blocking the threads executing particular thread function. If you want that the threads must pass from particular point of the code lines together, this member function of the manager object can be used. An example for the usage of wait member function blocking all of the threads executing the same thread function is shown in below figure.
In the figure that is given in above, the threads executing the thread function which is named as "Function_1" are stopped until all of the threads executing the same thread function performs a call to the same member function - wait("Function_1"). In other words, the threads cross over the wait member function together. There is another version of the same member function waiting a call to the its corresponding rescue member function form a thread executing a different thread function. An example that illustrates how this member function can be used is given in below.
8.2.5 The situation awareness in pcynlitx
In pcynlitx applications, you can get information about the stuation of a particular thread in terms of blocked/non-blocked. In pcynlitx, the control function that is used for this purpose is "Get_Block_Status()" member function. The return type of the member function is bolean. The trace of the member function is given in below.
A simple example that illustrates how this member function can be used is given in below figure. In the figure, an implementation of typical producer/consumer system has been depicted. In this typical example, the thread which is numbered as thread(0) reads a file and extracts some data from this file on the inside of a while loop. Then, it sends this extracted data into a buffer. Meanwhile, the thread which is numbered as thread(1) waits on the inside of the wait member function which is written on the inside of a do-while loop until the thread(0) sending a data into the buffer. After the data is sent into the buffer, the thread(0) sets the buffer empty condition as false and performs a call to the rescue(0) function. In this case, the thread(0) goes to the wait condition and thread(1) starts its execution. After that, thread(1) writes the collected data into a backup file and checks the status of the thread(0). If thread(0) is in the wait condition, then, thread(1) performs a call to the function rescue(0) and sets the buffer empty condition as true. This mechanism is very useful in order to prevent from the spurious wake ups. Moreover, this is not only benefit of retrieving status of the threads. In most cases, the errors that are faced on the multithread programming applications ( especially deadlocks ) occurs after a wrong rescue signal leading starting the execution of a thread before its time. Unfortunately, detection of this kind of errors is very hard. The logical understandability of the program to be developed can be listed as another benefits of this member function as well. However, in order to determine the status of the threads, the manager object have to collect information from the threads after each operation that is performed on the multi-threaded software. Therefore, the thread manager class has an array of bolean member holding the status of the threads. After each operation that is performed on the pcynlitx applications, the manager object updates its information about the status of the corresponding thread. For instance, on the inside of the wait and rescue member functions, the manager object's data members holding the status information the manager object is changed.
The pcynlitx platform provides more function retrieving information about the status of the threads. In pcynlitx, the other member function that retrieves information from the threads is "Get_Opt_Number( )". This member function returns the number indicating how many threads are running on the process currently.
8.2.6 Stop a thread until a particular thread completes its execution
In pcynlitx, you can stop a certain thread until another thread's execution will be completed. This is another spectacular control function that can be used on the multithread applications in which pcynlitx platform is used. The name of this member function is "wait_until_exit" and it takes two parameters. The first one of them is the number of the thread that will be stopped and the other parameter is the number of the thread in which its completion is waited by.
An example for the usage of this member function can be find on the example codes given on the project repository and formal web site. In fact, manager object provides much more control tools that can be used in thread synchronization. In the project web sites, there are many other introductory documents as well.
9. THE DECLERATION OF THE INTER-THREAD CLASSES
On the header files of the inter-thread classes, the parameter types and paramter names must be clearly specified. If the parameter names ara not clearly specifed on the decleration of the header files, the pcynlitx syntax controller gives error message. In order to make everything more clear, in the following, declaration type will be shown with examples.
In the example that is given in below, how the inter-thread class declaration must be performed has been shown. In the example, it has been assume that a simple class performing basic computing tasks is shared between the threads ( a typical inter-thread class ).
The Previous Page: The Programming Tutorial Page - 1