Ministry of Transport of the Russian Federation

Federal Agency for Railway Transport

GOU VPO "DVGUPS"

Department: "Information Technologies and Systems"

COURSE WORK

on the topic: "Process control subsystem"

Completed by: Sholkov I.D.

group 230

Checked by: Reshetnikova O.V.

Khabarovsk 2010

Introduction

1. Description of the program

1.1 Functional purpose

1.2 Technical means used to create the program

1.3 Multithreading and multiprocessing

1.4 Thread and Process Priorities

1.5 Methods for synchronizing streams

1.3 The logical structure of the program

2. User's manual for working with the program

2.1 General information and purpose of the program

2.2 Graphical interface

2.3 Working with the program

2.4 Main characteristics of ProcessManager

Conclusion

Bibliography

C # supports parallel code execution through multithreading. A thread is an independent execution path that can run concurrently with other threads.

A C # program runs as a single thread, automatically created by the CLR and the operating system (the "main" thread), and becomes multithreaded by creating additional threads.

Multithreading is managed by the thread scheduler, a function that the CLR usually delegates to the operating system. The thread scheduler ensures that active threads are allocated adequate execution time, and threads that are waiting or blocked, for example, waiting for an exclusive lock or user input, do not consume CPU time.

On uniprocessor computers, the thread scheduler uses time slicing - fast switching between the execution of each of the active threads. This leads to unpredictable behavior, as in the very first example, where each sequence of characters 'X' and 'Y' corresponds to a time slice allocated to the thread. In Windows XP, the typical time slice value - tens of milliseconds - is chosen to be much higher than the CPU cost of context switching between threads (a few microseconds).

On multiprocessor computers, multithreading is implemented as a mixture of time slicing and true parallelism, where different threads execute code on different CPUs. The need for time slicing still remains, since the operating system must serve both its own threads and the threads of other applications.

A thread is said to be preempted when its execution is suspended due to external factors such as time slicing. In most cases, a thread has no control over when and where it will be preempted.

All threads of one application are logically contained within a process - an operating system module in which the application is executed.

In some ways, threads and processes are similar — for example, time is shared between processes running on the same computer, just as it is between threads in the same C # application. The key difference is that the processes are completely isolated from each other. Threads share memory (heap) with other threads in the same application. This allows one thread to supply data in the background, while another can display the data as it arrives.

The Priority property determines how much execution time will be allocated to a thread relative to other threads in the same process. There are 5 grades of thread priority: enum ThreadPriority (Lowest, BelowNormal, Normal, AboveNormal, Highest)

The priority value becomes significant when multiple threads are running concurrently.

Setting the thread priority to the maximum does not mean real-time work, since there is still an application process priority. To work in real time, you must use the Process class from the System.Diagnostics namespace to raise the priority of the process.

There is one step from ProcessPriorityClass.High to the highest priority of the process - Realtime. By prioritizing a process in Realtime, you are telling the operating system that you want your process to never be preempted. If your program accidentally ends up in an infinite loop, the operating system can be completely blocked. In this case, only the power off button can save you. For this reason, ProcessPriorityClass.High is considered the highest usable process priority.

If a real-time application has a user interface, it may not be desirable to raise the priority of its process, since refreshing the screen will eat up too much CPU time - slowing down the entire computer, especially if the UI is complex enough.

The lock statement (aka Monitor.Enter / Monitor.Exit) is one example of thread synchronization constructs. Lock is the most suitable means for organizing exclusive access to a resource or section of code, but there are synchronization tasks (such as signaling the start of work to a waiting thread) for which lock will not be the most adequate and convenient means.

The Win32 API has a rich set of synchronization constructs, and they are available in the .NET Framework as the EventWaitHandle, Mutex, and Semaphore classes. Some are more practical than others: Mutex, for example, largely duplicates the capabilities of lock, while EventWaitHandle provides unique signaling capabilities.

All three classes are based on the abstract WaitHandle class, but behave quite differently. One of the common features is the naming ability, which makes it possible to work with threads of not only one but also different processes.

EventWaitHandle has two derived classes, AutoResetEvent and ManualResetEvent (which have nothing to do with C # events and delegates). All the functionality of the base class is available to both classes, the only difference is the invocation of the base class constructor with different parameters.

In terms of performance, all WaitHandles usually execute in the microsecond range. This rarely matters given the context in which they are applied.

AutoResetEvent is the most commonly used WaitHandle and the main synchronization construct, along with lock.

AutoResetEvent is very similar to a turnstile - one ticket allows one person to pass. The "auto" prefix in the name refers to the fact that an open turnstile is automatically closed or "reset" after it allows someone to pass through. The thread is blocked at the turnstile by calling WaitOne (wait (wait) at this (one) turnstile until it opens), and the ticket is inserted by calling the Set method. If multiple threads call WaitOne, a queue is formed behind the turnstile. Any thread can "insert" a ticket — in other words, any (non-blocked) thread that has access to an AutoResetEvent object can call Set to skip one blocked thread.

If Set is called when there are no waiting threads, the handle will remain open until some thread calls WaitOne. This feature helps to avoid races between the flow approaching the turnstile and the flow inserting the ticket ("oops, the ticket was inserted a microsecond earlier, it's a shame, but you'll have to wait a little longer!"). However, a repeated call to Set for a free turnstile does not allow a whole crowd to pass at a time - only one person can pass, all other tickets will be wasted.

WaitOne accepts an optional timeout parameter - the method returns false if the wait timed out rather than receiving a signal. WaitOne can also be trained to exit the current synchronization context to continue waiting (if using auto-blocking mode) to avoid excessive blocking.

The Reset method ensures that an open turnstile is closed without any waiting or blocking.

AutoResetEvent can be created in two ways. First, using its constructor: EventWaitHandle wh = new AutoResetEvent (false);

The task management system ensures their passage through the computer. Depending on the state of the process, it needs to allocate a particular resource. For example, a new process needs to be allocated in memory by allocating an address space; include in the list of tasks competing for CPU time.

One of the main subsystems of a multiprogrammed operating system that directly affects the functioning of a computer is process and thread management subsystem... She deals with their creation and destruction, and also distributes processor time between processes and threads simultaneously existing in the system.

When multiple tasks run concurrently on a system, although threads arise and execute asynchronously, they may need to interact, such as exchanging data. Therefore, thread synchronization is one of the important functions of the process and thread control subsystem.

Interaction between processes is carried out using shared variables and special basic operations called primitives.

The subsystem for managing processes and threads has the ability to perform the following operations on processes:

- creation (generation) / destruction of the process;

- suspension / resumption of the process;

- blocking / awakening of the process;

- starting the process;

- changing the priority of the process;

The process and thread management subsystem is responsible for providing the processes with the necessary resources. The OS maintains special information structures in memory, in which it records what resources are allocated to each process. A resource can be assigned to a process for its sole use or shared with other processes. Some of the resources are allocated to the process when it is created, and some are dynamically allocated on request at runtime. Resources can be assigned to a process for its entire life or only for a certain period. When performing these functions, the process control subsystem interacts with other OS subsystems responsible for resource management, such as the memory management subsystem, the I / O subsystem, and the file system.

1. Creating and deleting processes and threads

To create a process means first of all to create process descriptor, which is one or more information structures containing all the information about the process required by the operating system to manage it. This issue was considered in detail earlier, now we just recall that such information may include, for example, the process identifier, data on the location of the executable module in memory, the degree of process privilege (priority and access rights), etc.

Creating a process involves loading the codes and data of the executable program of this process from disk into RAM. In this case, the process control subsystem interacts with the memory and file system control subsystem. In a multithreaded system, when a process is created, the OS creates at least one thread of execution for each process. When creating a thread, just as when creating a process, the OS generates a special information structure - a thread descriptor, which contains the thread identifier, data on access rights and priority, on the state of the thread, etc. Once created, a thread (or process) is in a ready-to-run state (or in a dormant state for a special-purpose OS).

Creation and deletion of tasks is carried out according to the corresponding requests from users or from other tasks. A task can spawn a new task - in many systems, a thread can contact the OS with a request to create a so-called. descendant streams. A parent task is called an "ancestor" or "parent", and a child task is called a "child" or "child task". The "ancestor" can suspend or delete its child task, while the "child" cannot control the "ancestor".

Relationships between child threads and their parents are built differently in different operating systems. In some operating systems, their execution is synchronized (after the parent thread completes, all its descendants are removed from execution), in others, the descendants are executed asynchronously with respect to the parent thread.

After the process is completed, the OS "cleans up the traces" of its presence in the system - it closes all the files with which the process worked, frees up the RAM areas allocated for codes, data and system information structures of the process. Correction of OS queues and resource lists in which there were references to the process being terminated is in progress.

2. Scheduling and scheduling processes and threads

The planning strategy determines which processes are selected to be executed in order to achieve the set goal. The strategies can be different, for example:

- if possible, finish calculations in the same order in which they were started;

- give preference to shorter processes;

- to provide all users (user tasks) with the same services, including the same waiting time.

During the existence of a process, the execution of its threads can be interrupted and resumed many times.

The transition from the execution of one thread to another is carried out as a result planning and dispatching.

Planning threads are based on information stored in process and thread descriptors. Scheduling can take into account the priority of threads, their waiting time in the queue, the accumulated execution time, the intensity of I / O access, and other factors. The OS schedules the execution of threads regardless of whether they belong to the same or different processes. Scheduling is understood as the task of selecting such a set of processes so that they conflict as little as possible during execution and use the computing system as efficiently as possible.

In various information sources, there are different interpretations of the concepts of "planning" and "dispatching". So, some authors divide planning into long-term (global) and short-term (dynamic, i.e. the current most efficient allocation), and the latter is called dispatching. According to other sources, scheduling refers to the implementation of a decision made at the planning stage. We will stick with this option.

Planning includes the solution of two tasks:

determining the point in time to change the active stream;

selection for execution of a thread from the queue of ready threads.

There are many scheduling algorithms that solve these problems in different ways. It is the planning features that determine the specifics of the operating system. We will consider them a little later.

In most operating systems, scheduling is done dynamically, i.e. decisions are made during work based on an analysis of the current situation. Threads and processes appear at random times and terminate unpredictably.

Static the type of scheduling can be used in specialized systems in which the entire set of simultaneously executed tasks is predefined (real-time systems). The planner creates a schedule based on knowledge of the characteristics of a set of tasks. This schedule is then used by the operating system for scheduling.

Dispatching consists in the implementation of the solution found as a result of planning, i.e. in switching one process to another. Dispatching is reduced to the following:

saving the context of the current thread that you want to change;

starting a new thread for execution.

In the context of the thread, firstly, the state of the computer hardware at the time of interruption is reflected (the value of the command counter, the contents of general-purpose registers, the operating mode of the processor, flags, interrupt masks, and other parameters), and secondly, the parameters of the operating environment (links to open files, data on incomplete I / O operations, error codes performed by this thread of system calls, etc.).

In the context of a thread, one can distinguish a part common to all threads of a given process (links to open files), and a part related only to this thread (contents of registers, command counter, processor mode). For example, in the NetWare environment, there are three kinds of contexts — the global context (process context), the thread group context, and the single thread context. The relationship between the data in these contexts is similar to the relationship between global and local variables in a program. The hierarchical organization of contexts speeds up the switching of threads: when switching from the thread of one group to the thread of another group within the same process, the global context does not change, but only the context of the group changes. Switching global contexts occurs only when switching from the thread of one process to the thread of another process.

3. Scheduling algorithms

From the point of view of solving the first scheduling problem (choosing the moment in time to change the active flow) scheduling algorithms are divided into two large classes - preemptive and non-preemptive algorithms:

non-displacing- an active thread can be executed until it itself transfers control to the system so that it selects another ready thread from the queue;

displacing- the operating system decides to change the job being executed and switches the processor to a different thread.

The main difference between the named scheduling algorithms is the degree of centralization of the flow scheduling mechanism. Let's consider the main characteristics, advantages and disadvantages of each class of algorithms.

Non-preemptive algorithms... An application program, having received control from the OS, itself determines the moment of completion of the next cycle of its execution and only then transfers control to the OS using a system call. Consequently, the user's control of the application is lost for an arbitrary period of time. Developers need to take this into account and create applications so that they work as if "in parts", periodically interrupting and transferring control to the system, i.e. during development, the functions of the scheduler are also performed.

Dignity of this approach:

- interruption of the flow at an inconvenient moment for it is excluded;

- the problem of simultaneous use of data is being solved, since during each execution cycle, the task uses them exclusively and is sure that no one else can change them;

- higher speed of switching from stream to stream.

Disadvantages are difficult program development and increased requirements for the qualifications of the programmer, as well as the possibility of seizing the processor by one thread when it is accidentally or deliberately looped.

Preemptive Algorithms- cyclic, or circular type of scheduling, in which the operating system itself decides to interrupt the active application and switches the processor from one task to another in accordance with one or another criterion. In a system with such algorithms, the programmer does not need to worry about the fact that his application will be executed concurrently with other tasks. Examples include UNIX, Windows NT / 2000, OS / 2 operating systems. Algorithms of this class are focused on high-performance application execution.

Preemptive algorithms can be based on the concept of quantization or on a priority mechanism.

Quantization based algorithms... Each thread is provided with a limited continuous quantum of processor time (its value should not be less than 1 ms - as a rule, several tens of ms). A thread is transferred from an executing state to a ready state if the quantum is exhausted. The quanta can be the same for all streams or different.

When allocating quanta to a stream, different principles can be used: these quanta can be of a fixed value or change in different periods of the stream's life. For example, for some specific stream, the first quantum can be quite large, and each next quantum allocated to it may have a shorter duration (decrease to the specified limits). This creates an advantage for shorter threads, while running long-running tasks into the background. Another principle is based on the fact that processes that frequently perform I / O operations do not fully implement their allotted time slices. To compensate for this injustice, a separate queue can be formed from such processes, which has privileges in relation to other threads. When the next thread is selected for execution, this queue is first scanned, and only if it is empty, a thread is selected from the general queue ready for execution.

These algorithms do not use any prior information about the tasks. Service differentiation in this case is based on the "history of existence" of the flow in the system.

From the point of view of the second scheduling problem (the principle of choosing to execute the next thread), the algorithms can also be conditionally divided into classes: non-priority and priority algorithms. In the case of priority-free service, the next task is selected in a certain predetermined order without taking into account their relative importance and service time. When implementing priority disciplines, some tasks are given the priority right to get into the execution state.

Now let's look at some of the more common planning disciplines.


First-come-first-served service... The processor is allocated according to the FIFO (First In First Out) principle, i.e. in the order in which service requests are received. This approach allows the implementation of the strategy "finish computations in the order of their appearance, if possible." Tasks that were blocked in the process of being executed, after entering the ready state, are queued in front of those tasks that have not yet been executed. Thus, two queues are created: one from the tasks that have not yet been executed, and the other from the tasks that have passed from the waiting state.

This discipline is implemented as non-preemptive, when tasks free the processor voluntarily.

Dignity this algorithm is its ease of implementation. Disadvantage- with a large load, short tasks are forced to wait in the system for a long time. The next approach eliminates this disadvantage.

The shortest process is served first. According to this algorithm, the next thread to be executed is the thread with the minimum estimated time required to complete its work. Streams that have little time left before they finish are preferred here. This reduces the number of pending tasks on the system. Disadvantage it is necessary to know the estimated times in advance, which is not always possible. As a rough approximation in some cases, you can use the time spent by the thread when it was last taken over.

The algorithm belongs to the category of non-preemptive non-priority.

The named algorithms can be used for batch modes of operation, when the user does not expect a response from the system. On the other hand, for interactive computing, it is necessary first of all to ensure acceptable response time and equality in service for multi-terminal systems. For single-user systems, it is desirable that those programs with which they directly work have better response times than background jobs. In addition, some applications, while running without direct user interaction, must still be guaranteed to receive their share of the processor time (for example, an e-mail receiving program). Priority service methods and the concept of quantization are used to solve such problems.


Carousel discipline, or circularRR(Round Robin). This discipline belongs to preemptive algorithms and is based on quantization. Each task receives processor time in portions - quanta. After the end of the time slice, the task is removed from the processor and placed at the end of the queue of processes ready for execution, and the next task is accepted for servicing by the processor. For optimal operation of the system, it is necessary to correctly choose the law according to which time slices are allocated to tasks.

The size of the quantum is chosen as a compromise between the acceptable response time of the system to user requests (so that their simplest requests do not cause long waiting times) and the overhead of frequent task changes. When interrupting, the OS must save a sufficiently large amount of information about the current process, put the descriptor of the removed task in the queue, load the context of the new task. With a small time slice and frequent switching, the relative share of such overhead will become large, and this will degrade the performance of the system as a whole. With a large time slice and an increase in the queue of finished tasks, the response of the system will become poor.

In some operating systems, it is possible to specify explicitly the value of the time slice or the allowable range of its values. For example, on OS / 2, the CONFIG.SYS file uses the TIMESLICE statement to specify the minimum and maximum values ​​for a time slice: TIMESLICE = 32.256 indicates that the slice can be changed between 32 and 256 milliseconds.

This service discipline is one of the most common. In some cases, when the operating system does not explicitly support the discipline of carousel scheduling, such a service can be organized artificially. For example, some RTOS use scheduling with absolute priorities, and when priorities are equal, the principle of priority is applied. That is, only a task with a higher priority can remove a task from execution. If necessary, organize service evenly and equitably, i.e. so that all jobs receive the same time slices, the system operator can implement such a service himself. To do this, it is enough to assign the same priorities to all user tasks and create one high-priority task that should do nothing but be scheduled to run on a timer at specified time intervals. This task will only deactivate the current application, it will move to the end of the queue, and the task itself will immediately leave the processor and yield to the next process in the queue.

In the simplest implementation, the carousel service discipline assumes that all jobs have the same priority. If it is necessary to introduce a priority service mechanism, usually several queues are organized, depending on the priorities, and the service of the lower priority queue is transferred only when the higher priority queue is empty. This algorithm is used for scheduling in OS / 2 and Windows NT systems.

Priority planning.

An important concept behind many preemptive algorithms is priority maintenance. Such algorithms use the information in the stream descriptor - its priority. Priority is defined differently in different systems. In some systems, the highest priority value may be considered its numerically highest value, in others, on the contrary, the highest priority is considered to be zero.

Typically, the priority of a thread is directly related to the priority of the process in which the thread is running. Process priority assigned by the operating system when it is created, taking into account whether the process is a system or applied process, what is the status of the user who started the process, whether there was an explicit instruction from the user to assign a certain priority to the process. The priority value is included in the process descriptor and is used when prioritizing its threads. If a thread is not initiated by a user command, but as a result of a system call by another thread, then the OS must consider the parameters of the system call to prioritize it.

When scheduling program maintenance according to the algorithms described earlier, a situation may arise when some monitoring or control tasks cannot be implemented for a long period of time due to an increase in the load in the system (especially in RTOS). At the same time, the consequences due to untimely execution of such tasks can be more serious than due to non-execution of some programs with a higher priority. In this case, it would be advisable to temporarily change the priority of "emergency" tasks (for which the processing time allotted for them expires), and after execution restore the previous value. The introduction of mechanisms for dynamically changing priorities makes it possible to implement a faster system response to short user requests (which is important for interactive work), but at the same time guarantee the fulfillment of any requests.

So the priority can be static(fixed) or dynamic(a changing system depending on the situation in it). So-called base thread priority directly depends on the base priority of the process that spawned it. In some cases, the system can increase the priority of a thread (and to varying degrees), for example, if a slice of the allocated processor time has not been fully used, or lower the priority otherwise. For example, the OS gives higher priority to threads waiting for keyboard input and to a lesser extent to threads that perform disk operations. In some systems that use the dynamic priority mechanism, rather complex formulas are used to change the priority, which involve the values ​​of the basic priorities, the degree of load on the computing system, the initial priority value set by the user, etc.

There are two types of priority scheduling: service with relative priorities and service with absolute priorities... In both cases, the choice of a thread for execution is carried out in the same way - the thread with the highest priority is selected, and the moment of changing the active thread is determined differently. In a system with relative priorities, an active thread runs until it leaves the processor itself (it goes into a wait state, or an error occurs, or the thread ends). In a system with absolute priorities, interruption of an active thread, in addition to the indicated reasons, also occurs if a thread with a higher priority than the active one appears in the queue of ready threads. Then the running thread is interrupted and put into a ready state.

In a system with relative priority scheduling, switching overhead is minimized, but one task can take a long time on the processor. For time-sharing and real-time systems, this service mode is not suitable, but in batch processing systems (for example, OS / 360) it is widely used. Absolute priority scheduling is suitable for asset management systems where quick response to events is important.

Mixed planning used in many operating systems: priority-based scheduling algorithms are combined with the concept of quantization.

The heart of the UNIX operating system is the process control subsystem. Almost all of the kernel's actions are related to processes, be it servicing a system call, generating a signal, allocating memory, handling exceptions caused by the execution of a process, or providing I / O services at the request of an application process.
All the functionality of an operating system is ultimately determined by the execution of certain processes, just as run levels are nothing more than a convenient form of defining a group of running processes. The possibility of terminal or network access to the system, the various services traditional for UNIX - the printing system, remote FTP archives, e-mail and the teleconference system (news) - are all the result of certain processes. Processes in UNIX are inherently associated with two of the most important system resources, the processor and memory. As a rule, there are never "many" of these resources, and the operating system is actively competing for the right to own the processor and memory. And since UNIX is a general-purpose multitasking system, the task of equitably distributing this resource between tasks of different classes and with different requirements is not trivial.
Since a program launched for execution generates one or more
processes (or tasks). The process control subsystem controls:
  • Creating and deleting processes
  • Distribution of system resources (memory, computing resources) between processes
  • Synchronizing processes
  • Interprocess communication
Obviously, in the general case, the number of active processes exceeds the number of computer processors,
but only one process can be running on each processor at a time. The operating system controls the access of processes to computing resources,
creating the feeling of performing multiple tasks at the same time. A special kernel task called the scheduler resolves conflicts between processes in contention for system resources (CPU, memory, I / O devices). The scheduler starts the process for execution, making sure that the process does not take over shared system resources. The process frees the processor by waiting for a long I / O operation, or afterquantum of time. In this case, the scheduler picks the next highest priority process and startsto execute it.

Memory management module provides the allocation of RAM for application tasks. If there is not enough memory for all processes, the kernel moves parts of the process
or several processes to secondary memory (usually in a special area of ​​the hard disk), freeing up resources for the running process.

All modern systems implement so-called virtual memory: a process runs in its own logical address space, which can significantly exceed the available physical memory. Managing the virtual memory of a process is also the responsibility of the memory management module.
Interprocess communication module responsible for notifying processes about events using signals and provides the ability to transfer data between different processes.

Process control basics

A UNIX process is an executable image of a program that includes a memory mapping - the compiled executable file, i.e. o there are translations of program modules, high-level languages, into equivalent program modules of the languagelow level, such as:the stack, code and data of libraries, as well as a number of kernel data structures needed to control the process, which is a very important point for further understanding the principles of memory allocation, as one of the most important resources in the "competition" of processes, that is, data is structured! conditionally on:
  • Stack (c tech ) is a memory area in which the program stores information about called functions, their arguments and each local variable in functions. The size of the area can change as the program runs. When functions are called, the stack grows, and when completed, it shrinks.
  • Heap (to learning ) is an area of ​​memory where a program can do whatever it wants. The size of the area may vary. The programmer has the opportunity to use part of the heap memory using the malloc () function, and then this area of ​​memory is increased. The resources are returned using free (), after which the heap is reduced.
  • Code (one segment ) is an area of ​​memory that stores the machine instructions of a compiled program. They are generated by the compiler, but they can also be written by hand. Please note that this memory area can also be divided into three parts (text, data and BSS). This region of memory has a fixed size, determined by the compiler.UNIX. Professional programming art. 259

This will further (including) predetermine the emergence (existence) of segments and pages. A process uses various system resources at runtime — memory, processor, file subsystem services, and I / O subsystems. The harsh truth of any modern computing complex is that one processor can serve only one process at a time, which in turn predeterminedthe emergence (existence) of the "planner", by means of whichthe UNIX operating system provides the illusion of multiple processes running concurrently by efficiently allocating system resources among active processes without allowing any one of them to monopolize the use of those resources.

The newborn UNIX operating system had just two processes, one for each terminal connected to the PDP-7. A year later, on the same PDP-7, the number of processes increased markedly, a system call appeared fork... In the First Edition of UNIX, there was a call exec, but the operating system still only allowed one process to be allocated in memory at a time. After the implementation of the hardware memory management subsystem on the PDP-11, the operating system was modified, which made it possible to load several processes into memory at once, thereby reducing the time for saving the process image in secondary memory (on disk) and reading it when the process continued execution. Until 1972, however, UNIX was not truly multitasking because I / O remained synchronous and other processes could not run until their peer completed the I / O. True multitasking only came about after the UNIX code was rewritten in C in 1973. Since then, the fundamentals of process management have remained largely unchanged.


The process can be executed in two modes - in kernel mode ( kernel mode) or in task mode ( user mode). In task mode, a process executes application instructions that are valid at an unprivileged processor security level. In this case, the system data structures are not available to the process. When a process needs some kernel service, it makes a system call that executes kernel instructions that are at the privileged level.

Although kernel instructions are executed, this is on behalf of the process that made the system call. The execution of the process then goes into kernel mode. Thus, the kernel of the system protects its own address space from access by the application process, which can violate the integrity of the kernel data structures and lead to the destruction of the operating system.

Moreover, some of the processor instructions, for example, changing registers related to memory management, can only be executed in kernel mode.
Accordingly, the process image also consists of two parts: kernel mode data and task mode. A task mode process image consists of a segment of code, data, stack, libraries, and other data structures that it can directly access. A kernel-mode process image consists of data structures that are inaccessible to a task-mode process, which are used by the kernel to control the process... This includes data dictated by the hardware, such as register states, tables for memory mapping, and so on, as well as data structures that the kernel needs to service a process. Generally speaking, in kernel mode, a process has access to any area of ​​memory.

Process data structures

Each process is represented in the system by two main data structures proc and user,

described, respectively, in the files sys / proc.h and sys / user.h... The content and format of these structures is different for different versions of UNIX.

....................................................................................................

https://m.habr.com/ru/company/*nix<-----------
….................................................................................................
At any given time, the data of the structures proc for all processes must be present in memory, although the rest of the data structures, including the process image, can be moved to secondary memory, the swap area. This allows the kernel to have at hand the minimum information it needs to locate the rest of the process's data, even if it is not in memory. Structure proc is an entry in the system process table, which, as we just noticed, is always in RAM. The entry in this table for the currently running process is referenced by the curproc system variable. Every time a context switch occurs when processor resources are transferred to another
process, the value of the variable changes accordingly curproc which now points to the structure proc active process. Second mentioned structure user also called u-area or u-block, contains additional data about a process that is required by the kernel only during the execution of the process (that is, when the processor is executing instructions for a process in kernel mode or a task). Unlike structure proc addressed by pointer curproc, data user are located
(more precisely, displayed) in a specific place in the kernel virtual memory and are addressed to a variable u... Shown below are the two main data structures of a process and how they are addressed by the UNIX kernel.
V u-area stores data that is used by many kernel subsystems and not only for process control. In particular, it contains information about open file descriptors, signal disposition, process execution statistics, and stored register values ​​when the process is suspended. Obviously, the process should not be able to modify this data in an arbitrary way, so the u-area is protected from access in task mode. As can be seen from Fig., u-area also contains a fixed-size stack, system stack, or kernel stack. When a process runs in kernel mode, the operating system uses this stack rather than the normal stack of the process.

Process states

The life cycle of a process can be broken down into several states. The transition of a process from one state to another occurs depending on the occurrence of certain events in the system.
  • 1. The process runs in task mode. In this case, the processor executes the applied instructions of this process.
  • 2. The process runs in kernel mode. In this case, the processor executes system instructionsoperating system kernel on behalf of the process.
  • 3 ... The process is not running, but ready to run as soon as the schedulerwill select it (runnable state) The process is in the queue for execution and has allthe resources it needs, except for computing resources.
  • 4. The process is in a sleep state (asleep), waiting for an unavailablethe moment in the resource, such as the completion of an I / O operation.
  • 5. The process returns from kernel mode to task mode, but the kernel interrupts it and producesa context switch to start a higher priority process.
  • 6. The process has just been created by calling fork and is in a transitionalstate: it exists but is not ready to start and is not in a sleep state.
  • 7. The process executed the exit system call and entered the statezombies (zombie, defunct). As such, the process does not exist, but records remain,containing the return code and temporary statistics of its execution, available to the parent process.This state is final in the life cycle of the process.
It should be noted that not all processes go through all the many states listed above. The process begins its life path from the state 6 when the parent process makes a system call fork ()... After the process has been completely created, the process ends the "child" of the call and transitions to the state 3 ready to launch, waiting for its
execution queues. When the scheduler chooses a process to run, it transitions to the state 1 and runs in task mode. Execution in task mode is terminated by a system call or interrupt, and the process enters kernel mode, in which the system call or interrupt code is executed. The process can then return to task mode again. However, while executing a system call in kernel mode, a process may need a resource that is not currently available. To wait for access to such a resource, the process calls the kernel function sleep () and goes into sleep state 4 ... In this case, the process voluntarily frees up computing resources, which are allocated to the next highest priority process. When a resource becomes available, the kernel "wakes up the process" using the function wakeup () queues it up for execution, and the process enters the "ready to run" state 3 .
When computing resources are provided to a process, a context switch occurs, as a result of which the image, or context, of the current process is saved, and control is transferred to a new one. A context switch can occur, for example, if a process has entered a sleep state, or if a process with a higher priority than the current one is in a ready-to-start state. In the latter case, the kernel cannot immediately interrupt the current process and perform a context switch. The fact is that a context switch when executed in kernel mode can lead to a violation of the integrity of the system itself.
Therefore, the context switch is postponed until the process transitions from kernel mode to task mode, when all system operations have completed and the kernel data structures are in a normal state.
Thus, after the scheduler has chosen a process to start, the latter starts its
executing in kernel mode, where the context switch ends. Further condition
process depends on its history: if the process was just created or was interrupted, returning to task mode, it immediately switches to this mode. If a process starts executing after a sleep state, it continues to run in kernel mode, ending the system call. Note that such a process can be interrupted after the system call completes at the time of transition from kernel mode to task mode, if there is a higher-priority process in the queue. UNIX 4xBSD defines additional process states, primarily related to the job control system and the interaction of the process with the terminal. The process can be put into a "stopped" state using stop signals SIGSTOP, SIGTTIN or SIGTTOU... Unlike other signals, which are processed only for a running process, sending these signals causes an immediate state change. In this case, if the process is running or is in the queue to start, its state is changed to "stopped". If the process was in a sleep state, its state will change to "stopped in a sleep state". The exit from these states is carried out by the continuation signal SIGCONT in this case, from the "stopped" state, the process goes into the "ready to start" state, and for the process stopped in the sleep state, the next destination is to continue "sleep".
The described features are fully implemented in SVR4.

There is an exception for processes that are sleeping for
a low-priority event, that is, an event that is relatively unlikely to occur (for example, keyboard input that may not occur).

Finally, the process makes a system call exit () and ends its execution. The process can also be terminated by receiving a signal. In both cases, the kernel frees resources owned by the process, excluding the return code and its execution statistics, andputs the process into a "zombie" state. The process remains in this state until the parent process makes one of the system calls, after which all information about the process will be destroyed, and the parent will receive the return code of the terminated process.

Memory management principles

Marshal Kirk McCusick FreeBSD - Architecture and Implementation<<-----------PDF ст.166

Memory management part-1

12:51 - Address resolution 34:21 - Overlay, dynamic structures

59:26 - Linear continuous mapping - Piecewise linear (Art 25)


Memory management part-2

What happened in the beginning? OOP or virtual memory.

51:44 -> "Virtual Memory";<-(стр. 18)->56:03 -> "Segments";


Associative translation buffer, Translation lookaside buffer(TLB) is a specialized CPU cache used to accelerate the translation of a virtual memory address to a physical memory address.
https://ru.wikipedia.org
https://www.ibm.com/support/knowledgecenter/.performance/cache_tlbs.htm

One of the main functions of an operating system is efficient memory management.
Random access memory (RAM). Memory access times are only a few processor cycles, so working with data in memory ensures maximum performance.
This resource is usually limited. To a greater extent, this is true for a general-purpose multitasking operating system, such as UNIX.
Therefore, data that cannot be located in RAM is located on secondary storage devices, or in secondary memory, the role of which is usually performed
disk drives. The access time to the secondary memory is several orders of magnitude longer than the access time to the main memory and requires the active assistance of the operating system.
The UNIX memory management subsystem is responsible for fair and efficient allocation
shared resource of main memory between processes and for data exchange between main and secondary memory. Some operations are performed in hardware, by a device
memory management unit (MMU) of the processor under the control of the operating system, which achieves the required performance.
Primitive memory management greatly reduces the functionality of the operating system. Such systems, as a rule, allow loading a single task into a predetermined place in RAM and transferring control to it. In this case, the task receives
disposal of all computer resources (sharing them, of course, with the operating system),
and the addresses used by the task are the physical addresses of the main memory.
Since this method of launching and executing one program is by far the fastest, it is often used in specialized microprocessor systems, but is practically inapplicable in general-purpose operating systems such as UNIX.
A number of possibilities can be formulated that the memory management subsystem of a modern multitasking operating system should provide:

  • Performing tasks that are larger than the operational memory.
  • Executing partially memory-loaded tasks to minimizethe time of their launch.
  • Placing multiple tasks in memory at the same time to improve processor efficiency.
  • Placing a task in an arbitrary location in RAM.
  • Placing a task in several different parts of the RAM.
  • Sharing of the same memory areas by several tasks.For example, multiple processes running the same program might share a segment of code.
  • the ability to create machine-independent codes, that is, a priori there should be no connection between the program and physical memory.
All these features are implemented in modern versions of UNIX using virtual memory, the performance of the multitasking operating system as a whole largely depends on the efficiency of the implementation and operation of this subsystem. It allows you to give the application the illusion that a large amount of memory is available, while in reality the computer may have only a small amount of RAM. This requires defining an abstraction for an "address space" other than the physical location of memory. The program creates links to codes and data in its address space, such addresses must be converted to addresses of memory cells. Transferring information to main memory for use by a program and performing address translation at each access to memory forces both the software and hardware of the computer to perform joint actions.
PS: LINUX

Moreover, the process works with virtual addresses, not physical ones.

The conversion is done by calculation using descriptor tables and table catalogs.

Linux supports 3 levels of tables: first level table catalog ( PGD- Page Table Directory),

catalog of second-level tables ( PMD- Medium Page Table Diractory), and finally the descriptor table (PTE- Page Table Entry). In reality, not all levels may be supported by a specific processor,but the headroom allows to support more possible architectures (Intel has 2 levels of tables, and Alpha - as many as 3).

Conversion of a virtual address to a physical one takes place, respectively, in 3 stages. The pointer is taken PGD, which is present in the structure describing each process, is converted into a record pointer PMD and the latter is converted to a pointer in the descriptor table PTE... And finally, to the real address,pointing to the beginning of the page, add an offset from its beginning. A good example of such a procedure can be seen in the kernel function< partial_clear>.


Virtual and physical memory

Random access memory is one of the important components of a computer system. Early UNIX systems had 64 KB of RAM at their disposal, and this amount was clearly insufficient, modern computers have gigabytes of RAM, and this is still not enough.
Random access memory can be represented as a sequence of bytes, each of which has its own unique address, called a physical address. It is these addresses that the processor ultimately uses when exchanging data with RAM. However, the address space of a process differs significantly from the address space of physical RAM. Imagine that the address space of a process was directly mapped into RAM, in other words that the addresses used by the process were physical addresses. With this approach, a number of insurmountable obstacles would await us on the way to creating a multitasking system:
  • First, it is difficult to imagine a mechanism that protects the address space of one process,from the address space of another, or, more importantly, from the address space of the operating system itself.Since each process operates with physical addresses, there is no guarantee that the process will not accessmemory locations belonging to other processes or the system kernel.The consequences of such an appeal are likely to be very dire.
  • Secondly, already at the compilation stage, it would be necessary to provide for the distributionexisting physical address space. When launched, each process mustoccupy a contiguous and non-overlapping area of ​​physical addresses.
  • Third, such memory allocation between processes is unlikelywhether it can be called optimal. The volume of the physical operating roommemory will significantly limit the number of processes,simultaneously running on the system. So eight processes,each occupying 1MB of memory will exhaust 8MBRAM, and the operating system at medium loadhas over 80 processes!
All of these problems can be overcome using virtual memory.
However, the addresses used by applications and the kernel itself do not have to correspond to physical addresses. Virtual addresses are translated or mapped to physical ones at the hardware level with the active participation of the operating system kernel.The meaning of virtual memory is that each process runs in its own virtual address space.

Virtual address space is a process paradise.

  • First, the process creates a sense of exclusivity - after all, the entire address spacebelongs only to him.
  • Secondly, it is no longer limited by the amount of physical memory - virtual memory can significantlyexceed the physical. As a result, the processes become isolated from each other and do not haveopportunities (even if desired)"host" in the address space of a neighbor. Physical memory is allocated as much as possibleefficiently - it does not depend on the allocation of virtual memory of an individual process.
Obviously, a controlled mapping mechanism is needed to implement virtual memory
virtual address to physical. In modern computer systems, the display process is performed at the hardware level (using MMU) (MMU bit ("usability" bit)) to ensure high transmission speed.
The operating system manages this process.

Modern processors, as a rule, support address space pooling (segment - page memory organization):

v areas of variable size - segments and

v fixed-size areas - pages,

the concept of "page" can be interpreted as a way of organizing memory when physical memory is divided into blocks of a fixed size (512-2Kb, multiple of 2), like the concept of "segment", "page" is one of the fundamental abstractions in understanding the architecture and operation of operating systems ... In this case, for each segment or page, its own mapping of virtual addresses to physical ones can be specified.
The virtual address space of a process is usually sequentially structured within segments — code, data, stack, and libraries. The location of the corresponding areas of physical memory can have fragmented character. The size of virtual memory can significantly exceed the size of physical memory due to the use of secondary memory or a swap area - as a rule, disk space, where temporarily unused portions of the process address space can be stored. For example, if during execution of a process a virtual address is accessed for which a corresponding page of physical memory is present, the read or write operation will succeed. If there is no page in RAM, the processor generates a hardware interrupt called a page error ( page fault), in response to which the kernel determines the position of the saved page content in the swap area, reads the page into memory, sets the parameters for mapping virtual addresses to physical addresses, and tells the processor to repeat the operation. All of these actions are invisible to an application that works with virtual memory.
The mechanism for mapping virtual addresses to physical addresses (address translation) is essential

way depends on the specific hardware implementation. This section discusses the SCO UNIX virtual-to-physical mapping mechanism using the Intel processor family as an example. However, as with the rest of UNIX subsystems, the basic principles differ little, and this presentation will help you introduce memory management mechanisms and understand, if necessary, a specific implementation.

Segments

The Intel processor family allows memory to be partitioned into multiple logical chunks called segments. In this case, the address space of a process can be represented in the form of several logical segments, each of which consists of a continuous sequence of addresses lying in a given range. Segmentation-based address translation
provides an unambiguous mapping of segment addresses into a continuous sequence
physical addresses. In this case, the virtual address consists of two parts: the segment selector and
offsets from the start of the segment. Selector(more precisely, the selector field INDEX) indicates
a so-called segment descriptor containing parameters such as its location in memory,
size and access rights. The processor supports indirect addressing of segments through segment descriptors, which are located in special tables - memory areas pointed to by
dedicated processor registers. The operating system kernel is responsible for populating these tables and setting the register values. In other words, the kernel specifies the mapping, and the processor does the mapping in hardware. With this indirect addressing, logical segments are protected from each other, which ensures the integrity of the address space of the process and the kernel.
The segment descriptors are located in two system tables - the local descriptor table
(Local Descriptor Table - LDT) and the Global Descriptor Table ( Gdt).
As the name suggests, LDT provides translation of virtual addresses of process segments,
while GDT maintains the kernel address space (for example, when handling the system
call or interrupt) Each process creates its own LDT, while the GDT
shared by all processes. The information about the table the selector points to is in the selector itself.

1 5 3 2 1 0

INDEX TI RPL
Segment selector
  • Field INDEX is the number (index) of the descriptor in the descriptor table that shouldused when calculating a linear address.
  • Bit TI indicates which descriptor table should be usedØ - GDT compliant1 - corresponds to LDT
  • Field RPL used to control the access rights of the program to the segment. is requestedprivilege level and is one of the mechanisms for securing segments.For example, if a process while in task mode tries to access a segment,belonging to the kernel, the processor will generate an exception, in response to this, the kernel will send a SIGSEGV signal to the process.
Each LDT or GDT entry is a segment descriptor. Several types of descriptors are defined used for code, data and stack segments, as well as a number of descriptors,
through which multitasking and transfer of control from a non-privileged task, such as a process in task mode, to a privileged task, such as the kernel, are provided.
The descriptors used in the latter case are called gateways.

Segment descriptors (code, data, stack) have several fields:

  • Base Address This field stores the 32-bit address of the start of the segment. The processor adds to itoffset and gets a 32-bit linear address.
  • Limit This field defines the size of the segment. If the resultingthe linear address is outside the segment, the processor generates an exception.Segment boundaries allow the processor to detect common errors such as stack overflow,invalid pointers, invalid call addresses andtransitions. In the case when the operating system thinks thatout of segment is not an error(for example, on a stack overflow), it can expand the segment by allocatingadditional memory and request execution of the command again.
  • Privileges This field, called the Descriptor Privilege Level (DPL), defines the levelsegment privileges and is used in conjunction with the RPL selector field to allow or deny accessto the segment. To access the segment, the task must be at least the same levelprivileges likesegment, i.e. RPL DPL.
  • Sign of presence. This bit provides one of the mechanisms for implementing virtual memory.If the bit is not set, when trying to accessto the segment, the processor generates a special absence situationsegment, allowing the kernel to load the segment from secondary memory and repeat the instruction again,without affecting the execution of the process. However, in most modern versionsUNIX virtual memory is paging based,in which the segment is always present in memory, and the exchange between the operational andsecondary storage occurs at the page level.
  • Type This field defines the type of segment. The processor checks the typesegment for compliance with the command being executed. This, in particular, makes it impossible to interpretdata segment information as processor instructions.
  • Access rights This field defines the access rights that limit the setoperations that can be performed on a segment. For example,a segment of code is usually marked as executable and readable.Data segments can have read-only access,or for reading and writing.
The combination of selector and offset forms a logical address. CPU memory control unit
uses a selector to determine the corresponding descriptor. By adding the base segment address stored in the descriptor with an offset, the processor creates a linear address. If the paging mechanism is not in use, the resulting linear address is the physical one used for direct access to RAM. However, a segment-only virtual memory implementation is not flexible enough and is not used in modern versions. Memory management in most systems is paging-based. Segments are used by the kernel to house code, data, and the stack of a process, each with a base address of zero and a 3GB limit, that is, all addressable virtual memory minus 1GB used by the system kernel.
The distribution of the virtual address space between the kernel and processes is discussed in "".

Page mechanism

When implementing virtual memory based only on segmentation, the entire segment can either be present in RAM, or absent (more precisely, it can be in secondary memory or in the executable file of the process).
Since the segment size can be quite large, the simultaneous execution of several large processes will cause serious contention for memory resources, which in turn
will lead to an intensive exchange of data between the main and secondary memory. In addition, the exchange of regions of variable size, which are segments, is rather complicated and, although the fragmentation of memory will be small, it will lead to low efficiency of its use,
leaving a lot of wasted space.

The page engine provides much more flexibility. In this case, the entire virtual address space (4 GB for Intel processors) is divided into blocks of the same size, called pages. Most Intel processors operate in 4KB pages. As in the case of segmentation, the page can either be present in RAM,
or be in the swap area or executable file of the process. The main advantage of such a scheme is that the memory management system operates on regions of a sufficiently small
size to ensure efficient allocation of memory resources between processes.
The paging mechanism allows part of the segment to be in RAM and part to be absent. This gives the kernel the ability to place in memory only those pages that are currently being used by the process, thereby significantly freeing up RAM. Another advantage is that the pages of a segment can be located in physical memory in arbitrary place and order, which allows efficient use of free space.
This approach resembles the storage scheme for files on disk - each file consists of
a different number of storage blocks that can be located in any free areas of the disk drive. This leads to significant fragmentation, but significantly increases the efficiency of disk space utilization.

When using the paging mechanism, the linear address obtained as a result of the addition of the base segment address and the offset is also a logical address, which is additionally processed by the processor's paging unit. In this case, the linear address is considered by the processor to be in three parts.


Page Directory Entry, PDE- The first field of the address, bits 22 to 31, indicates an entry in the page table catalog PDE... The page table catalog is one page long and contains up to 1,024 pointers to page tables. Thus, the first field addresses a specific page table.
Page Table Entry, RTE- The second field, which is from 12 to 21 bits, indicates the element of the page table RTE... Page tables are also 4 KB in length, and table entries address a total of 1,024 pages. In other words, the second field addresses a specific page.
Finally, the page offset is determined by the third field, which occupies the least significant 12 bits of the linear address. Thus, with a single table catalog, a process can address

1024 x 1024 x 4096 = 4 GB of physical memory.

The figure above shows how the processor's paging block translates a linear address to a physical address. The processor uses the PDE address field (upper 10 bits) as an index in the table catalog. Foundthe element contains the address of the page table. The second field of the RTE line address, allows the processor to selectthe required element of the table that addresses the physical page. Adding the start of the page with an offset,stored in the third field, the processor gets a 32-bit physical address.

Most modern and, in particular, Intel processors, put data about the last few pages they used in a super-operative cache. Only when the processor does not find the required page in this cache does it refer to the catalog and page tables. As a rule, 99-98% of address links fall into the cache, without requiring the address to be accessed to the RAM, where the directory and tables are located, for translation.
Each page table element contains several fields that describe different

page characteristics. Fields PTE:


P
A sign of the presence in RAM. Accessing a page that is not in memory (P = 0) causes a page error, a special situation, which the processor informs the kernel about, which processes it accordingly.
R / W Read-only page (R / W = 0) or read-write (R / W = 1)

U / S
Access privileges. If U / S = 0, only privileged tasks(core) have access to page addresses. Otherwise, access topage have all tasks.
Address Physical address of the beginning of the page (base address)

Process address space

The kernel address space is usually the same as the address space of the currently running process. In this case, the kernel is said to be in the same context as the process. Every time computing resources are transferred to a process, the system restores
the task context of this process, which includes the values ​​of general registers, segment registers, and pointers to page tables that map the virtual memory of the process in task mode. In this case, the system context remains unchanged for all processes. The view of the address space of the process is shown in the figure below.

One of the main subsystems of any modern multiprogramming operating system that directly affects the functioning of a computer is a subsystem for managing processes and threads. The main functions of this subsystem:

    creation of processes and threads;

    providing processes and flows with the necessary resources;

    process isolation;

    scheduling the execution of processes and threads (in general, we should talk about scheduling tasks);

    dispatching threads;

    organization of interprocess communication;

    synchronization of processes and streams;

    termination and destruction of processes and threads.

1. Five main events lead to the creation of a process:

    fulfilling a request from a running process to create a process;

    prompting the user to create a process, for example, when logging into the system interactively;

    initiation of a batch job;

    creation by the operating system of a process necessary for the operation of any services.

Usually, when the OS boots, several processes are created. Some of these are high-priority processes that provide interaction with users and get the job done. The rest of the processes are background processes, they are not associated with specific users, but perform special functions - for example, related to e-mail, Web pages, output to seal, file transfer on network, periodic launch of programs (for example, defragment disks) etc. Background processes are called demons.

A new process can be created on request of the current process. The creation of new processes is useful in cases where the task being performed is most easily formed as a set of related, but, nevertheless, independent interacting processes. In interactive systems user can launch a program by typing a command on the keyboard or by double-clicking the program icon. In both cases, a new process is created and launch there are programs in it. V batch processing systems on mainframes, users submit a job (perhaps using remote access), and the OS creates a new process and starts the next job from the queue when the necessary resources are freed.

2. From a technical point of view, in all these cases, the new process is formed in the same way: the current process is performed by the system inquiry to create a new process. The subsystem for managing processes and threads is responsible for providing the processes with the necessary resources... The OS maintains special information structures in memory, in which it records what resources are allocated to each process. It can assign resources to a process for individual use or shared with other processes. Some of the resources are allocated to the process when it is created, and some are dynamically allocated on requests in lead time... Resources can be allocated to a process for its entire life or only for a certain period. When performing these functions, the process control subsystem interacts with other OS subsystems responsible for resource management such as the memory management subsystem, input-output subsystem, file system.

3. So that the processes cannot interfere with resource allocation, and also could not damage each other's codes and data, the most important task of the OS is to isolate one process from another... For this operating system provides each process with a separate virtual address space so that no process can directly access the commands and data of another process.

4. In an OS where processes and threads exist, a process is considered as an application for the consumption of all types of resources, except for one - processor time. This crucial resource distributed by the operating system among other units of work - threads, which got their name from the fact that they are sequences (threads of execution) of commands. The transition from the execution of one thread to another is carried out as a resultplanning anddispatching . Work on determining when to interrupt the execution of the current thread and the thread to be allowed to execute is called scheduling. Thread scheduling is based on information stored in process and thread descriptors. The planning takes into account thread priority, their waiting time in the queue, accumulated lead time, the intensity of I / O access and other factors.

5. Dispatching is the implementation of the solution found as a result of planning, i.e. in switching the processor from one thread to another. Dispatching takes place in three stages:

    saving the context of the current thread;

    starting a new thread for execution.

6. Additional problems arise when the system is running multiple independent tasks at the same time. Although threads arise and execute synchronously, they may need to communicate, for example, when exchanging data. Processes and threads can use a wide range of possibilities to communicate with each other: channels (in UNIX), mailboxes ( Windows), remote procedure call, sockets (in Windows connect processes on different machines). Consistency of thread rates is also very important to prevent the effect of "racing" (when several threads try to change the same file), deadlocks, and other collisions that arise when sharing resources.

7. Synchronization threads is one of the most important functions of the process and thread management subsystem. Modern operating systems provide many synchronization mechanisms, including semaphores, mutexes, critical regions, and events. All these mechanisms work with threads, not processes. That's why when flow is blocked on a semaphore, other threads in this process can continue to run.

8. Every time the process ends, - and this happens due to one of the following events: normal output, output on error, output on unrecoverable error, destruction by another process - the OS takes steps to "clean up the traces" of its presence in the system. The process control subsystem closes all the files with which the process worked, frees up the RAM areas allocated for codes, data and system information structures of the process. Performed correction all kinds of OS queues and list resources that contained references to the process being terminated.

process isolation;
  • scheduling the execution of processes and threads (in general, we should talk about scheduling tasks);
  • dispatching threads;
  • organization of interprocess communication;
  • synchronization of processes and streams;
  • termination and destruction of processes and threads.
  • There are five main events that lead to the creation of a process:

  • fulfilling a request from a running process to create a process;
  • prompting the user to create a process, for example, when logging into the system interactively;
  • initiation of a batch job;
  • creation by the operating system of a process necessary for the operation of any services.
  • Usually, when the OS boots, several processes are created. Some of these are high-priority processes that provide interaction with users and get the job done. The rest of the processes are background processes, they are not associated with specific users, but they perform special functions - for example, related to e-mail, Web pages, printing, transferring files over the network, periodically launching programs (for example, defragment disks) etc. Background processes are called demons.

    A new process can be created at the request of the current process. The creation of new processes is useful in cases where the task being performed is most easily formed as a set of related, but, nevertheless, independent interacting processes. On interactive systems, the user can launch the program by typing a command on the keyboard or by double-clicking the program icon. In both cases, a new process is created and a program is launched in it. V batch processing systems on mainframes, users submit a job (perhaps using remote access), and the OS creates a new process and starts the next job from the queue when the necessary resources are freed.

    From a technical point of view, in all these cases, the new process is formed in the same way: the current process fulfills the system request to create a new process. The process and thread management subsystem is responsible for providing the processes with the necessary resources. The OS maintains special information structures in memory, in which it records what resources are allocated to each process. It can assign resources to a process for individual use or shared with other processes. Some of the resources are allocated to the process when it is created, and some are dynamically allocated on request during lead time... Resources can be allocated to a process for its entire life or only for a certain period. When performing these functions, the process control subsystem interacts with other OS subsystems responsible for resource management such as the memory management subsystem, input-output subsystem, file system.

    So that the processes cannot interfere with resource allocation, and also could not damage each other's codes and data, the most important task of the OS is to isolate one process from another. For this operating system provides each process with a separate virtual address space so that no process can directly access the commands and data of another process.

    In an OS where processes and threads exist, a process is considered as an application for the consumption of all types of resources, except for one - processor time. This critical resource is shared by the operating system among other units of work - threads, which get their name from the fact that they are sequences (threads of execution) of commands. The transition from the execution of one thread to another is carried out as a result planning and dispatching... The work of determining when to interrupt the execution of the current thread and the thread to be allowed to run is called scheduling. Thread scheduling is based on information stored in process and thread descriptors. The planning takes into account thread priority, their waiting time in the queue, accumulated lead time, the intensity of I / O access and other factors.

    Dispatching is the implementation of the solution found as a result of planning, i.e. in switching the processor from one thread to another. Dispatching takes place in three stages:

    • saving the context of the current thread;
    • loading the context of the stream selected as a result of scheduling;
    • starting a new thread for execution.

    Additional problems arise when the system is running multiple independent tasks at the same time. Although threads arise and execute synchronously, they may need to communicate, for example, when exchanging data. Processes and threads can use a wide range of capabilities to communicate with each other: pipes (in UNIX), mailboxes (Windows), remote procedure calls, sockets (in Windows, processes on different machines are connected). Consistency of thread rates is also very important to prevent race conditions (when multiple threads try to modify the same file), deadlocks, and other collisions that occur when sharing resources.

    Synchronization threads is one of the most important functions of the process and thread management subsystem. Modern operating systems provide many synchronization mechanisms, including semaphores, mutexes, critical regions, and events. All of these mechanisms work with threads, not processes. Therefore, when a thread blocks on a semaphore, other threads in that process can continue to run.

    Each time a process exits - and this happens due to one of the following events: normal exit, exit by error, exit on fatal error, destruction by another process - the OS takes steps to "clean up" traces of its presence in the system. The process control subsystem closes all the files with which the process worked, frees up the RAM areas allocated for codes, data and system information structures of the process. Correction of various OS queues and a list of resources in which there were references to the process being terminated is performed.

    As noted to support multiprogramming, The OS must arrange for itself those internal units of work, between which the processor and other computer resources will be divided. The question arises: what is the fundamental difference between these units of work, what effect of multiprogramming can be obtained from their use, and in what cases should these units of work of the operating system be created?

    Obviously, any job of a computing system consists in the execution of some program. Therefore, a certain program code is associated with both the process and the stream, which is made out in the form of an executable module. In the simplest case, a process consists of a single thread, and in some modern operating systems this is the case. Multiprogramming in such operating systems it is carried out at the process level. If interaction is necessary, the processes turn to the operating system, which, acting as an intermediary, provides them with interprocess communication means - channels, mail shares, shared memory sections, etc.

    However, in systems that lack the concept of a thread, problems arise when organizing parallel computations within a process. And such a need may arise. The point is that a single process can never be executed faster than in single program mode. However, an application running within a single process may have internal parallelism, which, in principle, could speed up its solution. If, for example, the program provides for an appeal to an external device, then for the duration of this operation it is possible not to block the execution of the entire process, but to continue calculations in another branch of the program.

    Concurrent execution of multiple jobs within one interactive application improves user productivity. So, when working with a text editor, it is desirable to be able to combine the typing of new text with such lengthy operations as reformatting a significant part of the text, saving it to a local or remote disk.

    It is not hard to imagine a future version of the compiler that will be able to automatically compile source code files during pauses while typing a program. Then warnings and error messages would appear in real time, and the user would immediately see where he was wrong. Modern spreadsheets recalculate data in the background as soon as the user changes something. Word processors paginate text, check for spelling and grammar errors, print in the background, save text every few minutes, and more. In all these cases, threads are used as a means of parallelizing computations.

    These tasks could be assigned to a programmer who would have to write a dispatcher program that implements parallelism within a single process. However, this is very difficult, and the program itself would turn out to be very confusing and difficult to debug.

    Another solution is to create multiple processes for one application for each of the parallel