RU/2: Форум. Общение пользователей и разработчиков OS/2 (eCS). : Multithreading (IV)


Список сообщений | Написать новое | Ответить на сообщение | Домой Поиск:
Предыдущее сообщение | Следующее сообщение
From : ???
To : All
Subj : Multithreading (IV)

The Process/Thread Model

The process is how OS/2 manages all the system resources. Remember how OS/2
boots up. Basically, that is how every program or process in OS/2 is born. When a
user requests a program to be run, the loader brings that program into memory and
sets it up to be run. That is a very simple description of a very involved process.

When the loader sets up a program to run, it creates one thread to be the main
thread of the application. This thread executes code and, in that code, manipulates
system resources. One of the most powerful features of OS/2 is that a thread can
create other threads or even processes and sessions.

Other threads, processes, and sessions are created through sytem APIs, such as
DosCreateThread and DosExecPgm. Recall that the operating system has very few
threads of its own and uses application threads to do much of the work.

Now let us define some definitions of processes and threads in the scheme of things.

The process is how OS/2 manages all system resources. The process is the unit of
ownership, whereas the thread is the unit of execution. A PROCESS DOES NOT RUN;
a process owns things, such as memory, files, semaphores, and other system resources.
A PROCESS ALSO OWNS THREADS.

The THREAD IS THE UNIT OF EXECUTION IN OS/2. Each thread has its own context in
which it runs. A THREAD CONTEXT is a set of registers and what is called is an
EXECUTION INSTANCE. The context is a complete environment in which the thread
owning the context can run. A THREAD SWITCH by the scheduler is really just a context
switch.

Along with the registers and other information specific to that thread, the context
indicates a THREAD STATE. These states include:

-- running

-- blocked

-- and frozen.

This is the part of the thread context that is always accesses by the scheduler/dispatcher
to maintain the ready list and determine which thread is next to run.

Since the process is the owning entity, everything in that process has the ability to access
anything owned by it. This means that all threads within a process can access all of that
process's memory, files, and control structures. OS/2 protects applications or processes
from interfering with each other.

BUT NOTE:

However, all threads within a single process can access anything within that process.
This leads to some interesting dilemmas and design considerations.

OS/2's protection model resolves around the process. Recall, however, that a process
does not run - it owns, whereas a thread runs. When a thread is about to isssue an
instruction that would cause an ACCESS VIOLATION, the thread and its owning process
are terminated.

WHEN A PROCESS IS TERMINATED, everything the process owns is released, and all
threads belonging to that process are terminated.

It is vital that all threads of a process be terminated, since each thread has access to
all of the process's data. If one thread causes a violation, that means something the
process owns has gone wrong, whether it be a pointer or attempted access to the
hardware. The reason for terminating the entire process, and all of its threads along
with it, is that IF ONE THREAD OF THE PROCESS HAS GONE WRONG, THAN ALL INTEGRITY
OF THE PROCESS IS LOST. You can't count on anything being correct anymore.

If the other threads of the process tried to use a return code from the errant thread
or to use some common data structure, data could be corrupted or lost. By terminating
the entire process immediately, the system preserves the integrity of the data on the
disk associated with that process, along with the integrity of all other processes in the
system.


Priority
*******

One of the most important features of OS/2's multitasking and its management of
multiple tasks is priority of threads. Every thread in OS/2 has a priority. The priority of
a thread is a number relative to the priority number of the of the other threads in the
system. This is how the scheduler knows what threads to schedule next or whether
any thread preemption needs to be done.

THERE ARE 4 PRIORITY CLASSES IN OS/2, EACH HAVING 31 SUBLEVELS.

The classes, in order of highest priority to lowest, are

-- TIME CITICAL

-- FIXED HIGH (sometimes called the Server Class)

-- REGULAR Class

-- IDLE TIME Class

There is also a line in the CONFIG.SYS indicating whether priority is to be dynamic or
absolute. Usually, the PRIORITY line in Config.sys indicates dynamic priority. This is the
default as installed, but it can be changed by the user to absolute.

If priority is dynamic, the scheduler/dispatcher component of OS/2 will dynamically
modify priorities of threads based on which is in the foreground, on whether the thread
has been starved for a certain period of time, and other criteria.

In general, every thread created is initialized with a default priority somewhere in the
Redular Class. This priority can be subsequently modified, either by the thread itself
or by the scheduler/dispatcher.

If a thread is to modify its own priority, it can do so by a call to the OS/2 API
DosSetPrority. The parameters to this function are simple the new priority for the thread,
along with the scope. The scope indicates whether the new priority is for that thread
alone or for all threads in the process.

The Time Critical Class is for threads that perform, as you might guess, time-critical
operations. Examples would be threads communicating through a serial communications
port, where two-way response is critical to process function, or threads gathering data
from a peripheral device. It is rare for a Time Critical thread to be preempted, as it
can only be preempted by a higher-priority Time Critical thread.

The Fixed High Class is for those threads that need a somewhat higher priority than the
Regular Class, but are not really time-critical. An example may be a thread that reads
from a tape drive asynchronously. You would want a thread such as this to be of higher
priority than the threads reading the buffer being filled.

Let's look at this more carefully, to see why thread reading from a slower device needs
to be a higher priority than one that is CPU-bound and reading those buffers. Since the
thread reading the tape is I/O-bound, every time the request to read the tape goes to
the device, it will block and the CPU-bound thread reading the buffers will be dispatched.

Since it is CPU-bound, it will run to the end of its time slice unless it is preempted by
another thread. If left at the same priorities, the CPU-bound thread will starve the
I/O-bound thread. By bumping the CPU-bound thread's priority slightly higher than the
the CPU-bound thread's (not necessarily higher than every thread in the system), you
ensure that the I/O thread is dispatched whenever it is ready to run.

Regular Class is where every thread starts out. When a thread is created, either by
the loader when starting a process or when another thread calls the OS/2 API
DosCreateThread, its priority is in the Regular class. In this class, the scheduler
dynamically modifies priorities.

Every thread in the Regular class is eligible to have its priority modified by the scheduler/
dispatcher. Some examples of how priorities are modified include raising the priority of
threads belonging to the foreground process and boosting up priorities of threads that
have been waiting for processor time longer than others.

This dynamic modification occurs only within the Regular class. Don't use DosSetPriority
to change the priority of a thread within a Regular class, because it will likely be
changed by the scheduler/dispatcher soon afterward. In all other classes, any priority
set by the application will stay unless reset by the application.

There is one other fact to mention:

The scheduler/dispatcher will never modify the priority of a thread to take it out of the
Regular class. They will all stay Regular unless the application changes it to another
class.

Finally, the lowest class in the hierarchy is the Idle Class. This is like Time Critical and
Fixed High in that the scheduler does not modify priorities of threads in this class, and
will not lower a thread's priority from until the processor has nothing else to do.

This is useful for such tasks as a background file-mirroring program. Any type of
background task is a candidate for the Idle class. You don't want such a task preempting
"real" work, so the Idle class is the place for it.

This theme will repeated with some deeper viewpoints.











Thu 25 Dec 2003 16:44 Mozilla/4.61 [en] (OS/2; U)




Programmed by Dmitri Maximovich, Dmitry I. Platonoff, Eugen Kuleshov.
25.09.99 (c) 1999, RU/2. All rights reserved.
Rewritten by Dmitry Ban. All rights ignored.