Please enable JavaScript to view this site.

KOL/MCK - User Guide

thread

 

Just like the VCL, to organize an independent thread of commands (or thread of commands, thread is translated as "thread"), the KOL library has an object that is named the same - TThread. But, unlike VCL, in KOL you do not need to create a descendant of the TThread object type to organize your own thread. It is enough to assign an OnExecute event handler to it, and in it implement the code that will be executed when the thread is started. To start the thread, call the Resume method (newbies who are not familiar with this circumstance try to call the Execute method, but this does not lead to the desired results, since in this case the launch occurs in the same thread from which Execute was called).

 

There are several different constructors for organizing command flow:

 

NewThread - creates an object in the Suspended state. After such an object is created, it is possible to assign an event handler to it on the OnExecute event, and start the thread (Resume);

NewThreadEx(onexec) - creates an object, assigns the handler specified in the parameter to the OnExecute event, and starts it for execution (unless the onexec parameter is nil). Those. as a result of this construction of the thread, it starts working immediately. If the application is running on a machine with one processor, most likely, some part of the handler code (that is, the thread code) will be executed before control returns to the thread that created the object, at the point following the call to the NewThreadEx constructor;

NewThreadAutoFree(onexec) - creates and starts a thread object similarly to the previous constructor, but additionally provides automatic destruction of the object upon completion of the thread.

An important detail: the thread object in KOL does not allow itself to be started more than once. In any case, if the stream was terminated, i.e. there was a return from the OnExecute handler, the object is no longer needed. The difference in the third construction method is that the object itself is comfortable with calling the Free method when the handler completes.

 

Methods, properties and events of the TThread object:

 

Execute - this method is for internal purposes only (although it is declared in the public section). In principle, since this method is declared virtual, it is possible to inherit the TThread object, similar to how it is done in the VCL. But I prefer to use the more economical method of assigning a handler to the OnExecute event. This method is also more convenient, as it allows you to use the "mirror" component of the MCK, and generate code for the stream "visually". (Can you guess why the VCL does not have a design-time component to represent command streams, and the code has to be written by hand?);

Resume - puts the suspended (Suspended) thread in the "command execution" mode. If the thread is already running, this method does nothing. To start a thread, you should use this method, not Execute, otherwise the thread statements will be executed directly in the same thread from which Execute was called;

Suspend - suspends the execution of the thread. This method can also be executed in the suspended thread itself. In this case, the call to the Suspend method will return only when the Resume method is executed for it from another thread;

Suspended - verifies that the thread is "suspended";

Terminate - stops the thread using the TerminateThread API function. Unlike the VCL, this is not a normal shutdown method, but rather an emergency shutdown. In order to terminate the execution of a thread more safely, you should somehow notify your thread that it would be time for it to terminate (for example, set a flag in some global variable or in a field of an object known to the thread - and at least use its Tag property common to all descendants of TObj, including the TThread object). After that, you should wait for some time for your flow to take note of this information and end itself. Of course, the code for such interaction is entirely on the shoulders of the programmer, that is, on you;

Terminated - checks that the stream has terminated (not necessarily abnormally, using the Terminate method, maybe in the usual way - by returning from the OnExecute handler);

WaitFor - waiting for the completion of this thread, the return from this method occurs only when the thread has actually finished;

Handle - the system handle to the TThread thread object. It can be useful for any API calls, for example, it can be passed to the WaitForMultipleObjects and WaitForMultipleObjectsEx procedures;

ThreadID - one more descriptor of the command stream as a system object of the kernel level (kernel);

PriorityClass - thread priority class. I recommend especially not to overuse priority classes. Windows' way of serving tasks and threads is imperfect. The slightest increase in the priority of one of the threads often leads to the fact that only this thread is executed, and the rest are forced to stand idle while it has something to do (that is, until it stops itself, or does not request a long asynchronous I / O operation). Classes differ:

IDLE_PRIORITY_CLASS - lowest, i.e. the thread only works when the system has nothing else to do;

NORMAL_PRIORITY_CLASS - normal priority class;

HIGH_PRIORITY_CLASS - increased, i.e. all normal priority threads will run extremely slowly if at least one higher priority thread is running;

REALTIME_PRIORITY_CLASS - in real time: in general, everything stops, only this thread works, even the system in this mode will not be able to service the mouse if your thread is busy (hmm, is there a "reset" button on your computer?);

 

ThreadPriority - priority of a thread within its own priority class. Unlike the previous property, this is a softer (and less fatal) way of managing thread priorities. However, the picture is exactly the opposite: quite often, very little can be changed by controlling the priority using this property, if you do not use extreme values.

The following priorities are distinguished:

THREAD_PRIORITY_IDLE - lowest;

THREAD_PRIORITY_LOWEST - minimal, allowing the thread to run even when the system is not idle;

THREAD_PRIORITY_BELOW_NORMAL - reduced compared to normal;

THREAD_PRIORITY_NORMAL - normal;

THREAD_PRIORITY_ABOVE_NORMAL - higher than normal,

THREAD_PRIORITY_HIGHEST - increased;

THREAD_PRIORITY_TIME_CRITICAL — time-critical (this priority is good for a thread that processes events from a timer created in the same thread);

 

PriorityBoost - Enables or disables for all threads in the system at once (that is, in general in the entire system, according to the Win32 API help), a temporary increase in priority for threads leaving the waiting state for a system event. Usually, this behavior is the default behavior for the system, i.e. temporary increase in priority is allowed;

Data - an arbitrary pointer (or 32-bit number) associated with the stream object;

AutoFree - Set this property to true to provide automatic destroying of thread object when its executing is finished.

OnExecute - "event", which is used to assign code to be executed in a thread, without inheriting other object types from TThread. The termination of this handler means the end of the thread, its Terminated property is set to true. It is no longer possible to run the stream again. If one and the same thread is supposed to be used for multiple execution of tasks of the same type, then it is necessary in the handler to organize an "eternal" cycle of waiting for orders to complete these tasks. Of course, it is necessary to provide for an exit from this "eternal" cycle when some event occurs, otherwise the thread will have to terminate abnormally when the application is about to close;

OnSuspend - an event that is triggered immediately before the suspension of this thread. This event fires in the context of the thread that called the Suspend. In particular, if a thread suspends itself, then the handler is called in its context. When this event is fired, the thread is not yet suspended .;

OnResume - an event that is triggered after the thread resumes. The handler for this event is also called in the context of the command stream that called the Resume method. This means that, firstly, this handler, in principle, will never be called in the context of the resumed thread itself (since the thread cannot resume itself). And, secondly, by the time the handler for this event is triggered, the resumed thread by the time (or in the process) of calling the handler for this event, it is quite possible that it has already been stopped again (or even completed, and even destroyed as an object!);

Synchronize(method) - calls the specified method "synchronously" on the main thread. The Synchronize method should be used within the executing thread itself in order to provide safer execution of sections of code that you want to execute in the context of the main thread. By "main" thread is meant the command thread in which the Applet window object is created (and all forms should be created in the same thread, to avoid confusion). This method provides synchronization by sending (SendMessage) a message to the main window (applet), and as a result, the system "freezes" the sending thread until it returns from the method passed for execution in the main thread. This freezing does not make the thread "Suspended" in the usual sense; it cannot be "renewed" at this moment

SynchronizeEx(method, param)- similar to the previous method, with the only difference that the method must have (the only one, not counting Self) parameter, in the general case - a pointer. What kind of pointer it is is up to the programmer. I added such a method when I felt the need to not just synchronize some non-parameterizable action, and pass it some set of input data to work with. One parameter is, of course, not enough, but, in principle, you can pass anything through a pointer, you just need to declare your data structure and create a pointer type to it.

 

Like many other property and event-driven objects, there is a mirrored TKOLThread component for the TThread object in the MCK. It is enough to put it on the form, assign an event handler to the OnExecute event, and set up its other properties at the design stage to start building a multi-threaded application.

 

However, you should understand what command streams are and how to use them correctly so you don't run into big trouble. First of all, you need to clearly understand that the execution of code executed in a thread can be interrupted at any time by the system, at the boundary of any machine instruction (not even a Pascal operator), and control can be transferred to any other thread in the system or in your own application. And the main stream in this is not at all different from other streams.

 

This means that data (variables, descriptors of system objects) that are shared across multiple threads of execution must be protected. The most unpleasant thing that can happen is the destruction of objects (or freeing the memory of structures) in one thread, while they are being handled in another thread.

 

My recommendations:

 

Protect areas of code responsible for the creation and destruction of shared data using mutexes, semaphores, and critical sections;

Protect shared objects from premature destruction (using the RefCount property and the RefInc and RefDec methods);

Synchronize execution of actions that change the state of window objects with the main thread (methods Synchronize and SynchronizeEx);

Finally, avoid using too many threads in your application. If it is possible to solve the same problem without creating command flows, do it this way.

 

 

KOL / MCK User Guide - Created by Carl Peeraer - Diamant Soft, based on the work of Vladimir Kladov - Artwerp.be

  

Keyboard Navigation

F7 for caret browsing
Hold ALT and press letter

This Info: ALT+q
Nav Header: ALT+n
Page Header: ALT+h
Topic Header: ALT+t
Topic Body: ALT+b
Exit Menu/Up: ESC