Chapter Two: Process Description and Control (Tang Xiaodan's Operating System Notes) Super full and super detailed! ! !

Article Directory

Chapter 2: Process Description and Control

type of process

  • According to the authority to use resources: system process, user process

  • According to the dependence on the CPU: partial CPU process, partial I/O process

2.1 Predecessor Graph and Program Execution

2.1.1 Precursor graph

In order to better describe the sequence and concurrent execution of programs, a predecessor graph for describing the sequence of program execution is introduced.

The predecessor graph refers to a directed acyclic graph, which can be recorded as DAG, which is used to describe the sequence of execution between processes.

Each node in the graph can be used to represent a process or a program segment, or even a statement, and the directed edge between the nodes represents the partial order (directed order) or predecessor relationship between the two nodes.

Note that loops are not allowed in the predecessor graph, otherwise an impossible predecessor relationship will inevitably be generated.

2.1.2 Sequential execution of programs

Execute in a certain sequence, and run the next program segment only after the previous process segment is executed.

Examples of programs executed sequentially:
Program I: Input program: used to input user programs and data
Program C: Calculation program: Calculate the input data
Program P: Print program: Print calculation results.

Sequential Execution Flowchart

I
C
P

Sequential Execution Features

  1. Sequential: The processor executes in the exact order specified by the program
  2. Closedness: When the program is running, it monopolizes the resources of the whole machine. The state of the resource (except the initial state) can only be changed by this program. Once the program starts to execute, its result will not be affected by the outside world.
  3. Reproducibility: As long as the environment and initial state of the program execution are the same, when the program is executed repeatedly, no matter whether it is executed from beginning to end without stopping or "stop and go", the same result can be obtained.

2.1.2 Concurrent execution of programs

Why concurrent execution

Although the sequential execution of programs brings convenience, the utilization rate of system resources is very low. To do this, programs or program segments should be enabled to execute concurrently.

Necessary conditions for concurrent execution of programs: programs with no predecessor relationship

  • For a block with the following four statements:

    S1:a=x+2

    s2:b=y+4

    s3:c=a+b

    s4=d-c+b

S1
S3
S4
S2

It can be seen that: S; must be executed after a and lb are assigned; S must be executed after S; but S and S can be executed concurrently because they are independent of each other.

concurrent execution characteristics

  1. Intermittent
  2. loss of closure
  3. irreproducibility

For example: There are two programs A and B executed concurrently, they share a variable N

Program A: N=N+1; Program B: print(N); N=0;

Programs A and B run at different speeds (losing encapsulation, resulting in non-reproducibility)

-----> There are three situations in this question: A is faster than B, B is faster than A, and A is between B and A.

(assuming that the value of variable N is n at a certain moment)

A is faster than B: n+1, n+1, 0
B is faster than A: n, 0,1
A is between B and A: n, n+1,0

2.2 Description of the process

2.2.1 Definition and characteristics of a process

In a multiprogramming environment, program execution is concurrent execution, which determines that ordinary programs cannot participate in concurrent execution , otherwise the running of the program will lose its meaning.

In order to make programs execute concurrently, and to describe and control the concurrently executed programs, the concept of "process" is introduced.

​The process entity ( that is Usually, the process entity is simply referred to as a process.

  • Typical Process Definition
  1. A process is the sequential execution of a program

  2. A process is the activity that occurs when a program and its data execute sequentially on a processor.

  3. A process is a process in which a program with independent functions operates on a data set. It is an independent unit of the system for resource allocation and scheduling.

  • Definition of traditional OS process

​ A process is the running process of a process entity, and is an independent unit for the system to allocate and schedule resources.

process characteristics

Process and program are two completely different concepts. In addition to the PCB structure that the process does not have, it also has the following characteristics:

  1. dynamic. The essence of the process is the execution process of the process entity.
  2. concurrency. Multiple process entities co-exist in memory and can run concurrently for a period of time.
  3. independence. In a traditional OS, a process entity is a basic unit that can run independently , obtain resources independently , and accept scheduling independently .
  4. asynchronicity. Unpredictable speed, stop and go.
  • Similarities and Differences Between Processes and Programs
  1. Each process entity contains two parts, the program segment and the data segment, so the process and the program are closely related.
    But from a structural point of view, in addition to the program segment and data segment, the process entity must also contain a data structure, that is, the process control block PCB.

  2. A process is an execution process of a program, so it is dynamic; dynamicity is also manifested in the fact that a process is generated by creation, executed by scheduling, and destroyed by cancellation, that is, it has a certain life cycle.
    The program is just an ordered collection of a group of instructions, which can be permanently stored on a certain medium, and it does not have the meaning of movement, so it is static.

  3. Multiple process entities can be stored in memory at the same time and executed concurrently. In fact, this is the purpose of introducing processes.
    The concurrent execution of a program (when no process is created for it) is not reproducible, so the program cannot be executed concurrently correctly.

  4. A process is a basic unit that can run independently, allocate resources independently, and accept scheduling independently.
    A program (when no process is created for it) does not have a PCB, so it cannot run independently in a multiprogramming environment.

  5. There is no one-to-one correspondence between processes and programs

    • Multiple runs of the same program will form multiple different processes
    • One execution of the same program can also generate multiple processes
      (such as generating child processes through fork calls in UNIX)
    • And a process can also execute multiple programs
      (such as replacing the execution code of a process by calling exec in UNIX)

2.2.2 The basic state and transition of the process (▽)

Three basic states of a process

Generally speaking, each process should be in at least one of the following three basic states:

(1) Ready (Ready) state. (wait for CPU)

(2) Execution (Running) state. (execution process)

(3) Blocking (Block) state. (something is missing besides the CPU 一般是I\0)

Three basic state transitions

insert image description here

Figure 1. Transitions of the three basic states

Creation and Termination Status

(1) Creation status

  • First, the process applies for a blank PCB, and fills in the PCB with information for controlling and managing the process;

  • Allocate the necessary resources for the process to run;

  • Put the process into the ready state and insert it into the ready queue.

    Note: If the resources required by the process cannot be met, for example, the system does not have enough memory to allow the process to be loaded into it, the creation work has not been completed at this time, and the process cannot be scheduled to run, so the state of the process at this time is called for the creation state.

The creation state is introduced to ensure that the scheduling of the process must be performed after the creation work is completed, so as to ensure the integrity of the process control block operation. At the same time, the introduction of the creation state also increases the flexibility of management. The OS can postpone the submission of new processes according to the limitations of system performance or main memory capacity .

(2) Termination state

  • Wait for the operating system to take care of the aftermath
  • Finally its PCB is zeroed out and the PCB space is returned to the system.

When a process reaches its natural end point, or has an insurmountable error, or is terminated by the operating system, or is terminated by other processes with termination rights, it will enter the terminated state.

A process that enters the terminated state can no longer be executed, but a record is still kept in the operating system, which saves the status code and some timing statistics for other processes to collect.

Once other processes have finished extracting their information, the operating system will delete the process, that is, clear its PCB, and return the blank PCB to the system.

The five basic states and transitions of a process
insert image description here

Figure 2. Five basic states and transitions of a process

2.2.3 Suspended operation and transition of process state

Introduction of pending operations

Move part of main memory to external memory.

The reason for introducing the suspend operation is based on the following needs of the system and users:

  • end user needs
  • parent process request
  • The need for load regulation
  • operating system needs

Three process state transitions after the introduction of the suspend primitive operation

After introducing the suspend primitive and the activation primitive active, under their action, the process may have the following states

​A primitive is a piece of code that cannot be interrupted after execution

  • hang:

    • Active Ready ---> Static Ready
    • Active blocking ---> Static blocking
  • activation:

    • static ready --> active ready
    • Static blocking --> active blocking
      insert image description here
Figure 3. Process state diagram with pending state

Transitions of the five process states after the introduction of the suspend operation

After introducing the creation and termination states, the following situations should be considered when the process state is transformed:

  • NULL --> create
  • Create --> Activity Ready
  • create --> static ready
  • Execute -->
    insert image description here
    Terminate
    Figure 4. Process state diagram with created, terminated, and suspended states

2.2.4 Data structure of process management (things inside PCB)

1. Data structures used for management control in the operating system

In the computer system, a data structure is set for each resource and each process to represent its entity. For the 称之resource information table or process information table (consisting of PCB), the resource or process identification, description包含 , Information such as status and a batch of pointers .

Through these pointers, information tables of similar resources or processes, or resource information tables occupied by the same process can be classified and linked into different queues, which is convenient for the operating system to search.

These data structures managed by the OS generally fall into the following four categories:

Memory table, device table, file table, process table (process control block PCB)
insert image description here

Figure 5

The process control block is a data structure in the core of the operating system, which mainly represents the state of the process.

The function is to make a program (including data) that cannot run independently in a multi-programming environment become a basic unit that can run independently or a process that is executed concurrently with other processes.

In other words, the OS controls and manages concurrently executed processes according to the PCB. The PCB is usually a contiguous bank in the system memory footprint.

2. The role of process control block PCB

  1. Mark as a base unit for independent operation

  2. Intermittent operation can be realized

  3. Provide information needed for process management

  4. Provide information needed for process scheduling

  5. Synchronize and communicate with other processes

3. Information in the process control block

  1. A process identifier
    is used to uniquely identify a process. A process usually has two identifiers:
external identifier internal identifier
Convenient user (process) access Facilitate the use of the process by the system
Composed of letters and numbers A unique numeric identifier whose number (number) can be reused
provided by the creator operating system settings
  1. Processor state
     Processor state information is also called the context of the processor, which is mainly composed of the contents of various registers of the processor.
register type effect
general purpose register Accessible by user programs for temporary storage of information
instruction counter Store the address of the next instruction to be accessed
Program status word PSW Contains status information, such as condition code, execution mode, interrupt mask flag, etc.
user stack pointer Store process and system call parameters and call addresses. The stack pointer points to the top of the stack
  1. process scheduling information
  • Process state , indicating the current state of the process, which is used as the basis for process scheduling and swapping;
  • Process priority is an integer used to describe the priority level of the processor used by the process. Processes with higher priority should obtain the processor first;
  • Other information required for process scheduling , which are related to the adopted process scheduling algorithm, for example, the sum of the time that the process has been waiting for the CPU, the sum of the time that the process has been executed, etc.;
  • Event refers to the event that the process is waiting to happen when the process changes from the execution state to the blocking state, that is, the blocking reason
  1. Process control information (where resources are placed)
  • The address of the program and data , the memory or external memory (first) address of the program and data in the process entity, so that when the process is scheduled for execution, its program and data can be found from the PCB;
  • Process synchronization and communication mechanism , which is a necessary mechanism to realize process synchronization and process communication, such as message queue pointers, semaphores, etc., which may be placed in PCB in whole or in part;
  • Resource list , which lists all the resources (except CPU) required by the process during operation, and there is also a list of resources allocated to the process;
  • Link pointer , which gives the first address of the PCB of the next process in the queue where this process (PCB) is located.

4. Organization of process control blocks

  • In linear mode , all PCBs in the system are organized in a linear table, and the first address of the table is stored in a dedicated area of ​​memory.
    This method is simple to implement and has low overhead, but it needs to scan the entire table every time it is searched, so it is suitable for systems with a small number of processes.
  • Link mode , that is to link the PCBs with the same status process into a queue through the link word in the PCB respectively. (A single CPU has only one process in the execution state, and there is no execution queue) A ready queue, several blocking queues, and blank queues are formed.
    For the ready queue , PCBs are often arranged from high to low according to the priority of the process, and the process PCB with high priority is arranged in front of the queue.
    The PCB of the process in the blocked state is arranged into multiple blocking queues according to the different blocking reasons, such as the queue waiting for I/O operations to be completed and the queue waiting for memory allocation.
  • Indexing method , that is, the system creates several index tables according to the status of all processes, such as ready index table, blocked index table, etc., and records the first address of each index table in memory in some dedicated units of memory.

2.3 Process Control

Process control is the most basic function in process management. It
mainly includes functions such as creating new processes, terminating completed processes, placing processes that cannot continue to run due to abnormal conditions, and being responsible for state transitions during process running.

  • Process control is generally implemented by primitives in the kernel of the OS.

2.3.1 Operating system kernel

1. The execution state of the processor

To protect the system program

  • System state (management state, kernel state): The state when the system management program is executed. Has high privileges, can execute all instructions, access all registers and memory

  • User state (eye state): The state when the program is executed in the future. Has lower privileges, can only execute specified instructions, access specified registers and memory

2. The function of the operating system kernel

  1. Support function

(1) Interrupt processing

(2) Clock management

(3) Primitive operation

  • Interrupt (External Interrupt): Refers to the processor's response to asynchronous events that occur within or outside the system. Asynchronous events refer to events that occur randomly without a certain timing relationship, such as the completion of data transmission tasks by external devices, and the occurrence of certain real-time control devices.

  • Primitives: A process that is composed of several instructions and used to complete a certain function.

    The difference with general procedures is that they are "atomic operations". The so-called atomic operation means that all actions in an operation are either done or not done at all . In other words, it is an indivisible basic unit and, therefore, cannot be interrupted during execution . Atomic operations are executed in management mode (kernel mode) and reside in memory.

  1. Resource management function

(1) Process management

(2) Memory management

(3) Device management

2.3.2 Process creation

1. Process hierarchy

​ In the OS, a process is allowed to create another process. Usually, the process that creates the process is called the parent process, and the created process is called the child process. Child processes can continue to create more grandchildren, thus forming a hierarchy of processes.

​ In UNIX, a process and its descendants together form a process family (group).

insert image description here

Figure 6. Process tree

(▲) The event that caused the process to be created

In order to enable programs to run concurrently, processes should be created for them respectively

  • Typical events that cause a process to create another process fall into four categories:
    • User login
    • Job scheduling: transfer from external memory to memory to start execution
    • Provide services
    • application request

(▲) Process creation

Whenever there is a request to create a new process in the system, the OS calls the process creation primitive Create to create a new process in the following steps:

(1) Apply for a blank PCB , apply for a unique digital identifier (internal identifier) ​​for the new process, and request a blank PCB from the PCB collection.

(2) Allocate the resources required for the new process to run , including various physical and logical resources, such as memory, files, I/O devices, and CPU time.

(3) Initialize the process control block (PCB) .

(4) If the process ready queue can accept the new process , insert the new process into the ready queue .

Create process pseudocode:

Create(,,){
    
    //CPU的状态,内存,优先级
p=Get_New_PCB()//分配新的PCB
pid=Get_New_PID()//分配进程的PID
p->ID=pid;I//设置进程的PID
p->CPU_State=;//CPU的状态
p->Memory=M;//内存
p->Priority=Pi;//优先级
p->Status.Type=“Ready”;//进程状态
p->Status.List=RL; //进程队列RL:Ready List
Insert(RL, p);//将进程p插入就绪队列
Scheduler( );//调度程序

Create a process under Windows: CreateProcess ()

BOOL CreateProcess(  
 LPCTSTR lpApplicationName, // 应用程序名称  
 LPTSTR lpCommandLine, // 命令行字符串  
 LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程的安全属性  
 LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程的安全属性  
 BOOL bInheritHandles, // 是否继承父进程的属性  
 DWORD dwCreationFlags, // 创建标志  
 LPVOID lpEnvironment, // 指向新的环境块的指针  
 LPCTSTR lpCurrentDirectory, // 指向当前目录名的指针  
 LPSTARTUPINFO lpStartupInfo, // 传递给新进程的信息  
 LPPROCESS_INFORMATION lpProcessInformation // 新进程返回的信息  
);  

/**
第 1 个参数  lpApplicationName 是输入参数,指向启动进程的 exe 文件。
第 2 个参数  lpCommandLine 是输入参数,是启动进程的命令行中的参数。
  当这两个参数都不为 NULL 时,第 1 个参数指定要启动的进程 exe 文件(不带参数),第 2 个参数指定启动进程所需参数。第 1 个参数也可以为 NULL,此时第 2 个参数就不能为 NULL,在 lpCommandLine 需要指定出要启动的程序名以及所接参数,彼此间以空格隔开,其中第 1 个参数即是程序名。

第 3 个参数  lpProcessAttributes 是输入参数,指向 SECURITY_ATTRIBUTES 结构变量,是进程的安全属性,可以为 NULL 则使用默认的安全属性。
第 4 个参数  lpThreadAttributes 是输入参数,同第 3 个参数一样,指向 SECURITY_ATTRIBUTES 结构变量。
第 5个参数  bInheritHandles 是输入参数,表示新进程是否从调用进程处继承了句柄。
  如果参数的值为 TRUE,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限;如果设为 FALSE,那么不继承。
第 6 个参数  dwCreationFlags 是输入参数,表示进程的创建标志以及优先级控制。
如 : CREATE_NEW_CONSOLE 会使新建的控制台程序拥有一个新的控制台; DEBUG_PROCESS 调用进程将被当作一个调试程序,并且新进程会被当作被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
第 7 个参数  lpEnvironment 是输入参数,指向新进程的环境变量块,如果设置为 NULL,那么使用父进程的环境变量。
第 8 个参数  lpCurrentDirectory 是输入参数,指定创建后新进程的当前目录,如果设置为 NULL,那么就在父进程所在的当前目录。
第 9 个参数  lpStartupInfo是输出参数,指向一个用于决定新进程的主窗体如何显示的 STARTUPINFO 结构体,该结构里可以设定启动信息,可以设置为 NULL 。
第 10 个参数  lpProcessInformation 是输出参数,指向一个用来接收新进程的识别信息PROCESS_INFORMATION结构体。
*/

Simple call example

#include <windows.h>
int main(){
    
    
    STARTUPINFO si=(sizeof(si)};
    PROCESS_INFORMATION pi;
    char *ZW ="C:\\Windows\\system32\\notepad.exe";
    char *szCommandLine ="C:\\my.txt";
    CreateProcess(ZW,
                  szCommandLine,
                  NULL,NULL, FALSE,NULL,NULL,NULL,
                  &si,
                  &pi);
      return 0;
}

create new process

Create a process kernel object and create a virtual address space

Load the code and data of the EXE and/or DLL into the address space

Create main thread and thread kernel objects

Start the main thread and enter the main function (main)

2.3.3 Termination of process

1. The event that caused the process to terminate

  • normal end
  • abnormal end
  • External intervention

2. Process termination process

If an event that requires the process to be terminated occurs in the system, the OS will call the process termination primitive to terminate the specified process according to the following process:

(1) According to the identifier of the terminated process, retrieve the PCB of the process from the PCB collection, and read the status of the process from it;

(2) If the terminated process is in the execution state, the execution of the process should be terminated immediately, and the scheduling flag should be set to true to indicate that the process should be re-scheduled after being terminated;

(3) If the process has descendant processes, all descendant processes should also be terminated to prevent them from becoming uncontrollable processes;

(4) Return all resources owned by the terminated process either to its parent process or to the system;

(5) Remove the terminated process (PCB) from its queue (or linked list) and wait for other programs to collect information.

2.3.4 Process blocking and wake-up

1. Events that cause process blocking and wakeup

  • Failed to request shared resources from the system (PV operation)
  • Wait for some kind of operation to complete (I/O operation)
  • new data has not arrived
  • Waiting for new tasks to arrive

2. Process blocking process

The process being executed, if one of the above events occurs, the process will block itself by calling the blocking primitive block. It can be seen that blocking is an active behavior of the process itself.
After entering the block process, because the process is still in the execution state, it should stop the execution immediately, change the current state in the process control block from "execution" to blocking, and insert the PCB into the blocking queue.
If multiple blocking queues blocked by different events are set in the system, this process should be inserted into the blocking queue with the same event. Finally, switch to the scheduler for rescheduling, assign the processor to another ready process, and switch, that is, keep the processor state of the blocked process and set the CPU environment according to the processor state in the PCB of the new process.

3. Process wake-up process

When the event expected by the blocked process occurs, such as the I/O operation it started has completed, or the expected data has arrived, the wakeup primitive wakeup is called by the relevant process (such as the process providing data), which will Processes waiting for this event wake up.

The process of wakeup execution is: first remove the blocked process from the blocking queue waiting for the event, change the current state in its PCB from blocked to ready, and then insert the PCB into the ready queue.

2.3.5 Process suspension and activation

1. Suspension of the process

When there is an event that causes the process to be suspended, the system will use the suspend primitive suspend( ) to suspend the specified process or the process in the blocked state

The execution process of the suspend() primitive: first check the status of the suspended process, if it is in the active ready state, change it to static ready; for the process in the active blocking state, change it to static blocking. (memory to external storage)

  • Emphasis: The essence of suspension is to prevent the process from continuing to execute, and suspension is often used in process swapping.

2. Process activation process

When an event to activate a process occurs, the system will use the activation primitive active( ) to activate the specified process

active() primitive execution process activation primitive first transfers the process from the external storage to the internal memory, checks the current state of the process, if it is static ready, it changes it to active ready; if it is static blocking, it changes it to active blocking

2.4 Process Synchronization

If effective measures cannot be taken to properly manage the operation of multiple processes, it will inevitably cause confusion to the system due to the disorderly competition for system resources by these processes . As a result, there is uncertainty in the result of each treatment, that is, it shows its irreproducibility.

2.4.1 Basic Concepts of Process Synchronization

Introduction: Process synchronization is an OS-level concept. In a multi-program environment, there are different constraints between processes.

In order to coordinate this mutually restrictive relationship, realize resource sharing and process cooperation, thereby avoiding conflicts between processes, process synchronization is introduced.

  • The main task
    is to coordinate the execution order of multiple related processes, so that the concurrently executed processes can share system resources according to certain rules (or timing), and can cooperate well with each other, so that the execution of the program has reproducibility.

1. Two forms of constraints

(1) Indirect mutual constraint relationship: mutual exclusion problem (shared system resources, such as I\0 device, CPU) - is a special case of synchronization

(2) Direct mutual constraint relationship: synchronization problem

Some applications create two or more processes to complete a task. These processes will cooperate with each other to accomplish the same task.

A
缓冲区
B
figure 2

2. Critical resources

A resource that only one process can access at a time

Many hardware resources, such as printers, tape drives, etc., are critical resources, and mutual exclusion should be adopted between processes to share such resources.

3. Classic example producer-consumer problem

There is a group of producer processes that produce products and provide these products to consumer processes for consumption. In order to enable the producer process and the consumer process to execute concurrently, a buffer pool with n buffers is set between the two, and the producer process puts the product it produces into a buffer; the consumer process can Take product from a buffer to consume. Although all producer processes and consumer processes run asynchronously, they must be synchronized, that is, the consumer process is not allowed to fetch products from an empty buffer, and the producer process is not allowed to send to an existing buffer. Release product in a buffer that is full and has not yet been taken

how to achieve

Explanation: When a product is put in, the array pointer in of the temporarily stored product in the buffer is incremented by 1.
Since the buffer pool is organized as a circular buffer, in=(in+1)%n means + operation.
Output pointer out, out=(out+1)%n, when (in+1)%n == out, it means the buffer pool is full; when in==out, it means the buffer pool is empty.

data structure

int in=0,out=0//定义指针
int counter = 0;//定义计数器
item buffer[n];//分配缓冲区
局部变量:nextp//存放刚生产出来的产品
    ,nextc //存放每次要消费的产品
    
/*--------------------------------------------------------*/
    
void producer(void ){
    
    //生产者进程
   while(1){
    
    
   produce an item in nextp;//生产一个产品放在nextp
   while (counter==n);//判断缓冲区是否满了
   buffer[in] =nextp; //将产品存入缓冲区
   in=(in+1)%n;//修改缓冲区指针,指向下一个空位置
       counter++}//修改计数器
   } 
 void consumer(void){
    
     //消费者进程
     while(1){
    
    
       while (counter==0);//判断缓冲区是否为空
         nextc=buffer[out];
         out= (out+1)%n;
         counter--;
         consume the item in nextc;
     }
 }
  • Concurrent execution is irreproducible

    In order to prevent this kind of error, the key to solving this problem is to treat the variable counter as a critical resource, that is, make the producer process and the consumer process mutually exclusive access to the variable counter.

4. Critical section

It can be seen from the foregoing that, whether it is a hardware-critical resource or a software-critical resource, multiple processes must mutually exclusive access to it.
The section of code that accesses critical resources in each process is called a critical section.
Apparently, if it can be guaranteed that all processes enter their own critical section exclusively , then the mutually exclusive access of all processes to critical resources can be realized.
For this reason, before each process enters the critical section, it should first check the critical resource to be accessed to see if it is being accessed .

Add a piece of code for the above check before the critical section , and call this piece of code an entry section. A section of code called an exit
section should also be added after the critical section , which is used to restore the flag being accessed in the critical section to an unaccessed flag. The code in other parts of the process other than the above-mentioned entry area, critical area, and exit area are called remainder sections.

A cyclic process that accesses critical resources can be described as follows:

while(TRUE){
    
    
        进入区
        临界区
        退出区
        剩余区
        }

5. (▲) Rules to be followed by the synchronization mechanism

  • give way
  • wait if busy
  • bounded wait
  • give way to wait

Note: Limited waiting cannot wait for death; the right (to the CPU) cannot be busy waiting, and enter the blocking state (block) by itself.

(1) Dead waiting state: The process cannot enter the critical area at all within a limited time, but has been trying to enter, falling into a waiting state with no results.
(A waiting process that has not entered the critical area cannot obtain critical resources at all and enters the process. This kind of waiting is fruitless, and it is a dead wait~) At this time, you should give up this fruitless
thing and ensure that you wait for a period of time limited

(2) Busy waiting state: When a process is in a critical section, any process that tries to enter its critical section must enter a continuous loop of code and fall into a busy waiting state. Continuously testing a variable until a certain value occurs is called busy waiting.
(A waiting process that has not entered the critical area is constantly testing the value of the variable in the loop code segment, occupying the processor and not releasing it. This is a busy waiting state~) -> At this time, the processor should be released to let to other processes

(3) Limited waiting: For a process that requires access to critical resources, it should ensure that it can enter its own critical area within a limited time, so as not to fall into a "dead wait" state.
(The benefit is the process itself)

(4) Give up the right to wait: When the process cannot enter its own critical section, the processor should be released immediately to prevent the process from falling into a "busy waiting" state.
(Benefits are other processes)

2.4.2 Hardware synchronization mechanism

Although software methods can be used to solve the problem of mutual exclusion of processes entering the critical area, it is difficult and has great limitations, so it is rarely used now.
Correspondingly, at present, many computers have provided some special hardware instructions, which allow detection and correction of the contents of a word, or exchange of the contents of two words. These special instructions can be used to solve critical section problems.

Lock

  • When managing the critical section, the flag can be regarded as a lock
  • Lock open to enter, lock to wait
  • Each process that enters a critical section must first test the lock

1. Shutdown interrupt

Turn off the interrupt before entering the lock test, and the interrupt cannot be turned on until the lock test is completed and the lock is locked. In this way, during the execution of the process in the critical section, the computer system does not respond to interrupts, so that scheduling will not be triggered, and process or thread switching will not occur.
Thus, the continuity and integrity of the lock testing and locking operations are guaranteed, and mutual exclusion is effectively guaranteed.

Disadvantages of the off-interrupt method:

  • Misuse of shutdown power can lead to serious consequences;
  • If the interrupt is turned off for too long, it will affect the system efficiency and limit the ability of the processor to cross-execute programs;
  • The method of turning off interrupts is also not suitable for multi-CPU systems, because turning off interrupts on one processor does not prevent the process from executing the same critical section code on other processors.

2. Use the Test - and -Set command to achieve mutual exclusion

boolean TS(Boolean *lock){
    
     
    boolean old;
    old=*lock;
    *lock=TRUE;
    return old; 
}
//-----------------------------------
do{
    
    
    ...
    while TS(&lock);
    critical section;//临界区
    lock= FALSE;
    remainder section;
}
    while(TRUE);        

3. Use the Swap instruction to realize process mutual exclusion

This instruction is called swap instruction, also known as XCHG instruction in Intel 80x86, which is used to exchange the contents of two words.

void swap(boolean *a, boolean *b)
    boolean temp;
    temp =*a;
    *a= *b;
     *b = temp ;
}
//----------------------------------------------
do{
    
    
   key = TRUE;
    do{
    
    
        swap(&lock,&key);
    }while(key!=FALSE);
    critical section
    lock = FALSE;
    remainder section;
}while (TRUE)

  • Hardware synchronization features :

    Process mutual exclusion access can be realized

    When the critical resource is busy, there is a "busy waiting" state, which does not comply with the principle of "waiting for right"

    Difficult to solve complex synchronization problems

2.4.3 Signal amount (▲)

The process mutual exclusion problem of integer semaphore and record semaphore is aimed at the situation that multiple concurrent processes only share one critical resource.

The AND-type semaphore is a process that often needs to obtain two or more shared resources before it can perform its tasks.

1. Integer semaphore

An integer semaphore is defined as an integer representing the number of resources.
Except for initialization, it can only be accessed through atomic operations wait (S) and signal (S).
wait (S) is also called P operation, and signal (S) is also called V operation.

wait(S)
{
    
    
  while (S<=0);/*  do no-op */
  S=S--}

signal(S)
{
    
    
  S=S++;
}

wait(S) and signal(S) are atomic operations that execute without interruption. In addition, in the wait operation, the test of S and the S=S– operation cannot be interrupted. The semaphore can only be accessed through primitive operations and cannot be interrupted by process scheduling.

  • Disadvantages: "busy waiting" when the semaphore 'S<=0', does not follow the "right to wait"

2. Recorded semaphore The
recorded semaphore mechanism is a process synchronization mechanism that does not have a "busy wait" phenomenon.
But after adopting the strategy of "waiting for the right", there will be a situation where multiple processes are waiting to access the same critical resource .
For this reason, in the semaphore mechanism, in addition to an integer variable value used to represent the number of resources, a process list pointer list should be added to link all the above-mentioned waiting processes .

typedef struct {
    
    
  int value;
  struct process_control_block *list;//每一个块里面放的都是PCB,且进程堵塞原因一致
}semaphore;
wait(semaphore *S)
{
    
    
    S->value--;  //请求一个该类资源
    if (S->value<0)
 block(S->list); 
//该类资源已分配完毕,调用block原语,进行自我阻塞并放弃处理机、插入到信号量链表S.L中
}

signal(semaphore *S)
{
    
    
    S->value ++;  // 已经释放进程
    if(S.value<=0)
 wakeup(S->list);  // 相应的可以唤醒一个进程
}

Note :

(1) The absolute value of S->value is the number of blocked processes when the negative value is negative , and the positive number is the number of processes (the number of resources of this type).

(2) The initial value of S->value represents the number of a certain type of resource in the system , also known as resource semaphore.

(3) If the initial value of S->value is 1, it means that only one process is allowed to access critical resources , and the semaphore is transformed into a mutual exclusion semaphore.

3. AND semaphore

Assume that there are two existing processes A and B, both of which require access to shared data D and E, of course, shared data should be used as critical resources.

For this purpose, mutually exclusive semaphores Dmutex and Emutexo can be set respectively for these two data
process A: process B:
wait(Dmutex); wait(Emutex);
wait(Emutex); wait(Dmutex);

If processes A and B alternately perform wait operations in the following order:

process A: P(Dmutex); so Dmutex=0

process B:P(Emutex); so Emutex=0

process A:P(Emutex); so Emutex=-1 A blocks

process B:P(Dmutex); so Dmutex=-1B blocking

In the end, processes A and B will be in a deadlock.

The basic idea of ​​the AND synchronization mechanism
is to allocate all the resources needed by the process during the entire running process to the process at one time, and release them together after the process is used up.
For this reason, an AND condition is added to the wait operation, or called a simultaneous wait operation, that is, the Swait operation is defined as follows:

Swait (S1,S2,...,Sn)
{
    
    
    while(TRUE)
    {
    
    
        if(Si >= 1 && ...&& Sn>=1)  //每个资源都可用
        {
    
    
            for(i=1;i<n;i++)
                Si -- ;      //分配所有资源
            break;
        }
        else
        {
    
    
          //将进程放入与Si < 1的第一个Si相关联的等待队列中,并将该进程的程序计数设置为交换操作的开始
        place the process in the waiting queue associates with the first Si found with Si < 1,and set the program count of this process to the beginning of Swait operation}
    }
}

Ssignal(S1,S2,...,Sn)
{
    
    
    while(TRUE)
    {
    
    
        for (i=1;i<n;i++)
        {
    
    
            Si ++;  //释放所有资源
           //将与Si关联的队列中等待的所有进程移至就绪队列中。
        Remove all the process waiting in the queue associsted with Si into the ready queue.}
    }
}

4. Semaphore set (understand)

In the record-type semaphore mechanism mentioned above, the wait(S) or signal(S) operation can only add 1 or subtract 1 to the semaphore, which means that only one unit of certain critical resources can be performed at a time. application or release. When N units are needed at a time, N wait(S) operations are required, which is obviously inefficient and may even increase the probability of deadlock.

In addition, in some cases, in order to ensure the security of the system, when the amount of applied resources is lower than a certain lower limit, it must be controlled and not allocated.
Therefore, when a process applies for a certain type of critical resource, before each allocation, it must test the amount of resources to determine whether it is greater than the lower limit of allocation, and decide whether to allocate it.

For all the resources applied by the process and the different resource requirements of each type of resource, the application or release is completed in one P and V operation. The test value of the process on the semaphore S is no longer 1, but the lower limit value t of the resource allocation, that is, S≥t is required, otherwise it will not be allocated. Once the allocation is allowed, the process's demand value for the resource is d, which represents the amount of resources occupied, and proceed to S,= S;-di.

​ Swait(S1, t1, d4, …Sn tn dn);

​ Ssignal(S1, d1,… Sn, dn);

2.4.4 Application of semaphore (▲)

1. Use semaphore to realize process mutual exclusion
 In order to enable multiple processes to access a critical resource mutually exclusive, just set a mutual exclusion semaphore mutex for this resource , and set its initial value to 1, and then each process accesses the critical resource The critical section CS of the resource can be placed between the wait (mutex) and signal (mutex) operations.

  • Use semaphores to realize process mutual exclusion, and mutex is used as a mutual exclusion lock
  • Let mutex be a mutual exclusion semaphore, its initial value is 1, and its value range is (-1, 0, 1).
semaphore mutex=1; //只有一个资源
 PA()
{
    
    
      while(1)
      {
    
    
            wait(mutex);  //当 mutex < 0 时停止
             临界区
            signal(mutex); 
             剩余区
      }
}
 PB()
{
    
    
      while(1)
      {
    
    
             wait(mutex);  			
             临界区
            signal(mutex); 
             剩余区
      }
}

(1) wait and signal must appear in pairs
(2) lack of wait will lead to system confusion, and cannot guarantee mutual exclusion of resources in the critical section
(3) lack of signal will make critical resources never be released, so that resources due to waiting Blocked processes are not woken up

2. Use the semaphore to realize the predecessor relationship (synchronization relationship)

In order to realize sequential execution --> this predecessor relationship, only need

Make the process P1 and P2 share a common semaphore S, whose initial value is 0, put the signal operation behind the statement S1, and insert the wait operation before the S2 statement . Since S is initialized to 0, if P2 is executed first, it must be blocked. Only after process P1 executes S1 and signal (S) is S++, P2 process can execute S2 (wait before executing S2, so the initial value is 0 to do wait operation)

  • Key points of the previous trend graph: first, you need to know who is blocking the process; second, you need to know which process to wake up;

2.4.5 Monitor Mechanism

  • Problems with the semaphore mechanism: programming is difficult and error-prone
  • In 1973, Brinch Hansen first introduced the "monitor" component - an advanced synchronization mechanism - into the programming language (Pascal)

1. Definition of monitor (secretary of the process)

The so-called monitor refers to the management of shared variables and the operation process of shared variables, so that they support concurrency.

The shared data structure can be used to abstractly represent the shared resources in the system , and the specific operations implemented on the shared data structure can be defined as a group of procedures.
The application, release and other operations of shared resources must go through this group of processes.
A monitor defines a data structure and a set of operations that can be performed by concurrent processes . This set of operations can synchronize processes and change data in the monitor .

2. Four parts of the tube process

  • the name of the monitor;
  • Description of the shared data structure of local and monitor
  • A set of procedures that operate on the data structure
  • A statement that sets the initial value for the shared data of the local and the monitor

The composition of the tube

  • a lock
    • Mutually exclusive access to control monitor code
  • 0 or more condition variables
    • Manage concurrent access to shared data

insert image description here

Figure 7. Schematic diagram of the tube process
Monitor monitor_name //管程名
{
    
    
      share variable declarations;//共享条件变量;
      cond declarations;  //条件变量
public:
      void P1(){
    
    } //PV操作
      void P2(){
    
    }
{
    
    initialization code;//初始化} 
}

3. Condition variables
When using monitors to realize process synchronization, synchronization tools must be set, such as two synchronization operation primitives wait and signal.
  When a process requests critical resources through the monitor but fails to meet them, the monitor calls the wait primitive to make the process wait and puts it on the waiting queue. Only after another process completes the access and releases the resource, the monitor calls the signal primitive again to wake up the leader process in the waiting queue.

Notes:
(1) The monitor must explain each condition variable in the form: condition x,y
(2) The variable should be placed before wait and signal, which can be expressed as X.wait and X.signal

For example: the calling process waits because the shared data is occupied, the form of the condition variable is: condition nonbusy
wait primitive ———> nonbusy.wait or cwait(nonbusy)
signal primitive ———> nonbusy.signal

  • The role of the X.signal operation: restart a blocked process. If there is no blocked process, the X.signal operation has no consequences. This is different from the signal operation in the semaphore mechanism, because the semaphore mechanism always performs s=s+1operations and always changes the state of the semaphore.

4. The difference between a process and a monitor
①The properties of the data structure are different
②The operations performed are different
③The purpose of the setting is different
④The working method is different
⑤Whether it has concurrency ⑥Whether
it is dynamic
5. The characteristics of the monitor
①Modularity
②Abstract data Type
③ information masking

2.5 Synchronization problems of classic processes

2.5.1 Producer-consumer problem

Problem description :

  • Producer-consumer is an abstraction of mutual cooperation process relationship: input, calculation, output
  • A group of producers produce products for consumers to consume
  • Share a buffer pool with n buffers
  • The producer's product is put into the pool, and the consumer takes the product from the pool for consumption
  • Producers and consumers must be synchronized, stop production when the pool is full, and stop consumption when the pool is empty
  • Access to critical resources (public variables) must be mutually exclusive
1. Use record semaphore to solve producer-consumer problem (▲)

Assuming that there are n buffers in the shared buffer pool between the producer and the consumer , then you can use the mutual exclusion semaphore mutex ( initial value 1 ) to realize the mutual exclusion of the process on the buffer pool; use the semaphore empty (initial value The value is n) and full (the initial value is 0) respectively represent the number of empty buffers and full buffers in the buffer pool.
  Assuming that these producers and consumers are equivalent to each other, as long as the total buffer is not full, the producer can send a message to the buffer pool, and as long as the buffer pool is not empty, the consumer can take a message from the buffer pool

int in=0, out=0;
// item 为消息的结构体
item buffer[n];
semaphore mutex =1; //缓冲区互斥操作的互斥信号量
semaphore empty = n; //空缓冲区数目,类型为资源信号量
semaphore full = 0; //满缓冲区为数目,类型为资源信号量

void producer(){
    
    
	do{
    
    
		// 生产者产生一条消息
		producer an item next p;
		......
		// 判断缓冲池中是否仍有空闲的缓冲区
		P(empty);
		// 判断是否可以进入临界区(操作缓冲池)
		P(mutex);
		// 向缓冲池中投放消息
		buffer[in] = nextp;
		// 移动入队指针
		in = (in+1) % n;
		//退出临界区,允许别的进程操作缓冲池
		V(mutex);
		// 缓冲池中数量的增加,可以唤醒等待的消费者进程。
		V(full);
	}while(true);
}

void consumer(){
    
    
	do{
    
    
		//判断缓冲池中是否有非空的缓冲区(消息)
		P(full);
		// 判断是否可以进入临界区(操作缓冲池)
		P(mutex);
		nextc = buffer[out];
		// 移动出队指针
		out = (out+1) % n;
		// 退出临界区,允许别的进程操作缓冲池
		V(mutex);
		// 缓冲池中空缓冲区数量加1, 可以唤醒等待的生产者进程
		V(empty);
		// 消费消息
		consumer the item in next c;
	}while(true);
}

2. Use AND semaphore to solve producer-consumer problem
  • Use Swait(empty,mutex) instead of wait(empty) and wait(mutex)
  • Use Ssignal(mutex,full) instead of signal(mutex) and signal(full)
  • Use Swait(full,mutex) instead of wait(full) and wait(mutex)
  • Use Ssignal(mutex,empty) instead of signal(mutex) and signal(empty)
int in=0, out=0;
// item 为消息的结构体
item buffer[n];
semaphore mutex =1; //缓冲区互斥操作的互斥信号量
semaphore empty = n; //空缓冲区数目,类型为资源信号量
semaphore full = 0; //满缓冲区为数目,类型为资源信号量

void producer() //生产者进程
{
    
    
      while(1)
      {
    
    
            produce an item nextp;
            Swait(empty,mutex)
            buffer[in] = nextp;
            in = (in+1)%n; //循环队列
            Ssignal(empty,mutex); //解锁
      }
}
void consumer() //消费者进程
{
    
    
      while(1)
      {
    
    
            Swait(full,mutex)
            nextc = buffer[out];
            out = (out+1)%n; //循环队列
            Ssignal(empty,mutex)
            consumer the item in nextc;
      }
}
3. Using monitors to solve the producer-consumer problem

Create a monitor and name it producerconsumer, or PC for short. It includes two processes:
(1) put(x) process . Producers use this process to put their own products into the buffer pool, and use the integer variable count to indicate the number of products in the buffer pool. When count >= n, it means that the buffer pool is full and the producer is waiting. (It means that there are 2 conditional variables)
(2) get(x) process . The consumer uses this process to take out a product from the buffer pool. When count <= 0, it means that there is no available product in the buffer pool, and the consumer waits.

For the condition variables notfull and notempty, there are two processes cwait and csignal to operate on them:
(1) cwait(condition) process : When the monitor is occupied by a process, other processes block when calling this process and hang on the condition On the condition queue
(2) csignal(condition) process : wake up the process blocked on the condition condition queue after cwait is executed, if there are more than one such process, select one of them to implement the wake-up operation ; if the queue is empty, no operation and return

monitor producer-consumer //类似于一个类
{
    
    
      int in=0,out=0,count=0;
      itm buffer[n];
      condition notfull,notempty;
      void put(item nextp)
      {
    
    
            if count >= n then 
                  cwait (notfull)//判断是否满了
            buffer [in]=nextp;
            in= (in+1)%n;
            count =count +1;
            csignal(notempty);
      }
      void get(item *x)
      {
    
    
            if count <= 0 then 
                  cwait (notempty)
            *x=buffer[out];
            out= (out+1)%n;
            count =count - 1;
            csignal(notfull);  //告诉生产者你可以生产了
      }
}PC;
//利用管程解决生产者-消费者问题
process producer()
{
    
    
      item x;
      while (TRUE)
      {
    
    
            produce an item in x;
            PC.put(item);  //相当于调用方法
      }
}
process consumer()
{
    
    
      item x;
      while (TRUE)
      {
    
    
            PC.get(item);
            consumer an item in x;
      }
}

2.5.2 Dining philosophers problem

Problem description :

5 philosophers sit at a table with 5 bowls and 5 chopsticks. The way of life of philosophers is to think and eat alternately. When philosophers are hungry, they pick up the chopsticks on both sides to eat, but only when they get You can only eat with two chopsticks, put down the chopsticks after eating, and continue to think.
Small extract:

  • think about the problem
  • Hungry, stop thinking, hold a chopstick in left hand (if the philosopher on the left is already holding it, need to wait)
  • Hold a chopstick in the right hand (wait if the philosopher on the right is already holding it)
  • meal
  • put right hand chopsticks
  • put left chopsticks
  • back to thinking
semaphore chopstick[5]={
    
    11111};
semaphore mutex = 1; //设置取筷子的信号量
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
    
    
      while( 1 )
      {
    
    
 
            P(chopstick[i]); //画个圈你就知道,这是他左手边的筷子
            P(chopstick[i+1] % 5
              ...
            //eat
            V(chopstick[i+1] % 5);  //释放右边筷子
            V(chopstick[i]); //释放左边
            //think
      }
}

The above solution can guarantee that no two adjacent philosophers can eat at the same time, but it may cause a deadlock.

1. Solve the dining philosophers problem by using the record semaphore mechanism

Method 1: Mutual exclusion to eat

At most four philosophers are allowed to take the chopsticks on the left at the same time, and it is guaranteed that at least one philosopher can eat at the same time, and after eating, release the two chopsticks

semaphore chopstick[5]={
    
    11111};
semaphore eating = 4; //仅允许四个哲学家可以进餐
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
    
    
      while( 1 )
      {
    
    
            P(eating); //请求就餐,若是第五个则先挨饿
            P(chopstick[i]); //画个圈你就知道,这是他左手边的筷子
            P(chopstick[i+1] % 5);
            eating();  //进餐
            V(chopstick[i+1] % 5);  //释放右边筷子
            V(chopstick[i]); //释放左边
            V(eating);  //释放信号量给其他哲学家
      }
}

Method 2: The action of holding chopsticks is mutually exclusive

Eat only when the philosopher's left and right chopsticks are available

semaphore chopstick[5]={
    
    11111};
semaphore mutex = 1; //设置取筷子的信号量
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
    
    
      while( 1 )
      {
    
    
            thinking();
            P(mutex); //在取筷子前获得互斥量
            P(chopstick[i]); //画个圈你就知道,这是他左手边的筷子
            P(chopstick[i+1] % 5);
            V(mutex);  //释放互斥量
            eating();  //进餐
            V(chopstick[i+1] % 5);  //释放右边筷子
            V(chopstick[i]); //释放左边
      }
}
2. Using the AND semaphore mechanism to solve the dining philosophers problem

Each philosopher is required to obtain two critical resources (chopsticks) before eating, which is essentially an AND synchronization problem, so using the AND semaphore mechanism to solve the philosopher’s dining problem is the most concise solution

semaphore chopstick[5]={
    
    11111};
process(i)
{
    
    
      while(1)
      {
    
    
            think;
            Swait(chopstick[i+1] % 5,chopstick[i]); //把两个筷子全拿起来
            eat;
            Ssignal(chopstick[i+1] % 5,chopstick[i]);      
      }
}

2.6 Process communication

2.6.1 Types of process communication

There are four major categories of high-level process communication tools: 1. Shared memory 2. Pipeline communication 3. Message passing systems 4. Client-server systems

  1. shared storage

    • In a shared memory system, communicating processes share the same data structures or memory areas
    • Processes can communicate through these shared memory spaces

    It can be further divided into the following two types:

    1. Based on the shared data structure : such as the shared buffer in the reader and writer, the OS only provides the shared storage area, and the programmer is responsible for the synchronization implementation. Low efficiency, belongs to low-level tools
    2. Based on the shared storage area : first apply, then attach, then use, and finally return
  2. pipeline communication system

    • A pipe is a shared file used to connect a reading process and a writing process, also called a pipe file
    • First created in UNIX
    • Read and write data is sent from the writing process to the reading process through the pipe in the form of a character stream

    The pipeline mechanism provides three coordination capabilities

    1. mutually exclusive
    2. Synchronize
    3. Determine whether the other party exists, and communicate only when the other party is determined to exist
  3. messaging system

    • The formatted message is used as the unit to encapsulate the data in the message, and use a set of communication commands/primitives (send, receive) provided by the OS to realize data exchange
    • Hide communication details, which is an advanced communication method
    • Computers are widely used, such as microkernel-server. Also applicable to multiprocessors, distributed systems, and computer networks

    Divided into two categories:

    1. Direct Messaging: Send directly to the other party
    2. Indirect messaging: complete sending and receiving through intermediate entities (mailboxes)
  4. client-server system

    • Client/server system is common in the field of computer network

    Divided into three categories:

    1. socket

    2. Remote Procedure Call (RPC)

    3. Remote Method Call (RMC)

      • socket

        • Originated in UNIX in the 1970s
        • It is network communication under UNIX operating system
        • Originally designed for communication between multiple applications on a host
        • Socket is currently the most popular network communication interface, specially designed for C/S model
        • A socket is a data structure used for communication, including destination address, port number, transmission protocol, network address of the process, etc.
        • Multiple system calls: listen, bind, connect, accept, read, write, close
      • remote procedure call

        • Remote Procedure (Function) Call RPC, is a communication protocol used to connect systems over a network
        • This protocol allows a process on a host (local) system to call a process on another host (remote) system, similar to a normal procedure call
        • Both the local and the host need to run the network daemon, which is responsible for network message delivery

2.6.2 Implementation of message passing communication

  1. direct messaging system

    Direct communication primitives fall into two categories:

    1. Symmetric addressing mode (1 to 1)

    2. Asymmetric addressing mode (1 to many)

    Message format:

    1. The transmitted message must have a certain message format
    2. In a stand-alone environment , since the sending and receiving processes are in the same machine and have the same environment , the message format is simple , and a relatively short fixed-length message format can be used to reduce the processing and storage overhead of the message.
    3. The fixed-length format is inconvenient for users who need to send longer messages . A variable length message format is available for this purpose . For variable-length messages, the system may pay more in terms of reprocessing and storage, which is a bit convenient for users.

    The synchronization method of the process:

    1. The sending process is blocked, and the receiving process is blocked;
    2. The sending process is not blocked, and the receiving process is blocked;
    3. Neither the sending process nor the receiving process blocks;

    communication link

  • To communicate between the sending process and the receiving process, a communication link must be established between the two.
    1. The command (primitive language) requests the system to establish a communication link for it, and remove the link after the link is used up. ( Network )
    2. Using the sending command (primitive language) provided by the system, the system automatically establishes a communication link for it. ( stand-alone system )
  1. mailbox communication

(1) The structure of the mailbox: the definition of the mailbox is a data structure

Logically divided into two parts ( this is very similar to the function of sending emails in life )

  • mailbox header
  • Mailbox body

insert image description here

Figure 8. Schematic diagram of two-way mailbox

(2) Primitives of mailboxes ( the system provides several primitives for mailbox communication )

  • Creation and cancellation of mailboxes
  • Sending and receiving of messages

(3) Types of mailboxes (slightly note that there are test points)

According to different mailbox creators, it is divided into the following three categories:
private mailbox ( the mailbox disappears after the process ends )
, public mailbox ( OS creates and assigns it )
, and shared mailbox

2.6.3 Example of a direct messaging system

Message buffer queue communication mechanism (widely used in local processes): the sending process uses the Send primitive to send messages directly to the receiving process, and the receiving process uses the Receive primitive to receive the message.

  1. Data structure in message buffer queue communication mechanism

    (1) Message buffer

    typedef struct message_buffer {
    int sender;  //发送者进程标识符
    int size;    //消息长度
    char *text;  //消息正文
    struct message_buffer *next;  //指向下一个消息缓冲区的指针
    }
    
    

    (2) Data items related to communication in the PCB

    typedef struct processcontrol_block {
          
          
        ...
    struct message_buffer *mq; //消息队列队首指针
    semaphore mutex;  //消息队列互斥信号量
    semaphore sm;  //消息队列资源信号量.
        ...
    }PCB
    
    

insert image description here

Figure 2. Message buffer communication
  1. send primitive

​ The sending primitive first applies for a buffer i according to the message length a.size set in the sending area a , and then copies the information in the sending area a to the buffer i . In order to hang i on the message queue mq of the receiving process, first obtain the internal identifier j of the receiving process, and then hang i on j.mq. Since the queue is a critical resource , the wait and signal operations must be performed before and after the insert operation.

  • send primitive description
void send(receiver,a){
    
    
    getbuf(a.size, i);
    copy(i.sender,a.sender);
    i.size=a.size;
    copy(i.text,a.text);
    i.next=O;
    getid(PCBset,receiver.j);
    wait(j.mutex);
    insert(&j.mq,i);
    signal(j.mutex);
    signal(j.sm);
}
  1. receive primitive

The receiving process calls the receiving primitive receive(b), removes the first message buffer i from the target message buffer queue mq , and copies the data in it to the specified message receiving area with b as the first address.

  • accept primitive description
void receive(b){
    
    
    j=internal name;
    wait(j.sm);
    wait(j.mutex);
    remove(j.mq,i);
    signal(j.mutex);
    copy(b.sender,i.sender);
    b.size =i.size;
    copy(b.text,i.text);
    releasebuf(i);
}

2.7 The basic concept of thread (Threads)

2.7.1 Introduction of threads

The purpose of introducing processes in the OS is to enable multiple programs to execute concurrently to improve resource utilization and system throughput. Then, introducing threads in the operating system is to reduce the time and space overhead of programs during concurrent execution . , so that the OS has better concurrency.

  1. Basic properties of the process
  (1) A process is an independent unit that can own resources (2) A process is also a basic unit that can be independently scheduled and dispatched.
  1. The time and space overhead required for concurrent execution of
    processes In order to enable concurrent execution of programs, the system must perform the following series of operations:
  • To create a process, when the system creates a process, it must allocate all resources necessary for it, except for the processor, such as memory space, I/O devices, and build the corresponding PCB;
  • To undo the process, when the system undoes the process, it must first perform recovery operations on the resources it occupies, and then undo the PCB;
  • Process switching, when a process is context switched, it is necessary to retain the CPU environment of the current process and set the CPU environment of the newly selected process, so a lot of processor time must be spent.
  1. as the basic unit of scheduling and allocation

Separate the two basic attributes of the process: as the basic unit of scheduling and dispatching, not as a unit with resources at the same time, so as to "travel lightly";

  • For the basic unit that has resources, it does not switch frequently.

2.7.2 Comparison of threads and processes

characteristic process thread
basic unit of scheduling In a traditional OS, a process is a basic unit for independent scheduling and allocation, so a process is a basic unit that can run independently. Every time it is scheduled, context switching is required, and the overhead is high. In the OS that introduces threads, threads have been regarded as the basic unit of scheduling and allocation, so threads are the basic units that can run independently. In the same process, thread switching will not cause process switching, but when switching from a thread in one process to a thread in another process, it will inevitably cause process switching.
concurrency Processes can execute concurrently. In the OS that introduces threads, not only processes can be executed concurrently, but also multiple threads in a process can be executed concurrently, and even all threads in a process can be executed concurrently. Likewise, threads in different processes can execute concurrently. This makes the OS have better concurrency, which can more effectively improve the utilization rate of system resources and the throughput of the system.
have resources Processes can own resources and serve as a basic unit of resource ownership in the system. The thread itself does not own system resources, but only a few essential resources that can guarantee independent operation. In addition to having a small amount of resources of its own, threads also allow multiple threads to share the resources owned by the process. This is first manifested in: all threads belonging to the same process have the same address space, which means that threads can access the address space Each virtual address in the process; in addition, you can also access the resources owned by the process.
independence There is independence between different processes. The independence between different threads in the same process is much lower than that between different processes. This is because, in order to prevent mutual interference and destruction between processes, each process has an independent address space and other resources, except for sharing global variables, access by other processes is not allowed. However, different threads in the same process are often created to improve concurrency and cooperate with each other, and they share the memory address space and resources of the process.
system overhead When creating or canceling a process, the system must allocate and reclaim process control blocks for it, and allocate or reclaim other resources, such as memory space and I/O devices. The overhead paid by the OS for this is significantly greater than the overhead paid for thread creation or cancellation. Similarly, during process switching, process context switching is involved, and the cost of thread switching is much lower than that of . In Solaris2OS, thread creation is 30 times faster than process creation, and thread context switching is 5 times faster than process context switching. In addition, since multiple threads in a process have the same address space, the synchronization and communication between threads is also simpler than that of a process. Therefore, in some OSs, thread switching, synchronization, and communication do not require the intervention of the operating system kernel.
Support for multiprocessor systems In a multiprocessor system, for a traditional process, that is, a single-threaded process, no matter how many processors there are, the process can only run on one processor. For a multi-threaded process, multiple threads in a process can be assigned to multiple processors to make them execute in parallel, which will undoubtedly speed up the completion of the process.

2.7.3 Thread state and thread control block

  1. Thread running state : execution state, ready state, blocking state
  2. Thread Control Block TCB

Just as each process has a process control block, the system also configures a thread control block TCB for each thread, and records all information used to control and manage threads in the thread control block.

  • Thread identifier, giving each thread a unique thread identifier;
  • Register status, including the contents of the program counter PC, status registers, and general-purpose registers;
  • Thread running state, which is used to describe the running state of the thread;
  • Priority, which describes the priority of thread execution;
  • The thread-specific storage area is used to store site protection information and statistical information related to the thread when the thread is switched;
  • Signal shielding, that is, shielding certain signals;
  • Stack pointer, which usually saves local variables and return addresses in the stack;
  1. Process attributes in multi-threaded OS

通常在多线程OS中的进程都包含了多个线程,并为它们提供资源。OS支持在一个进程中的多个线程能并发执行,但此时的进程就不再作为一个执行的实体。多线程OS中的进程有以下属性:

(1)进程是一个可拥有资源的基本单位

(2)多个线程可并发执行

(3)进程已不再是可执行的实体

2.8线程的实现

2.8.1 线程的实现方式

  1. 内核支持线程KST

支持线程KST同样也是在内核的支持下运行的,它们的创建、阻塞、撤消和切换等,也都是在内核空间实现的。

  • 优点:
  1. 在多处理器系统中,同一进程中的多个线程可以并行执行;
  2. 如果进程中的一个线程被阻塞了,内核可以调度该进程中的其它线程占有处理器运行,也可以运行其它进程中的线程;
  3. 线程的切换比较快,切换开销小;
  4. 内核本身也可以采用多线程技术,可以提高系统的执行速度和效率。
  • 缺点

同一进程下的线程切换开销比较大。

  1. 用户级线程ULT

用户级线程是在用户空间中实现的。对线程的创建、撤消、同步与通信等功能,都无需内核的支持,即用户级线程是与内核无关的。

  • 优点
  1. 线程切换不需要转换到内核空间。
  2. 调度算法可以是进程专用的。
  3. 用户级线程的实现与OS平台无关,因为对于线程管理的代码是属于用户程序的一部分,所有的应用程序都可以对之进行共享。
  • 缺点:
  1. 系统调用的阻塞问题。在基于进程机制的OS中,大多数系统调用将使进程阻塞,因此,当线程执行一个系统调用时,不仅该线程被阻塞,而且,进程内的所有线程会被阻塞。而在内核支持线程方式中,则进程中的其它线程仍然可以运行。
  2. 在单纯的用户级线程实现方式中,多线程应用不能利用多处理机进行多重处理的优点,内核每次分配给一个进程的仅有一个CPU,因此,进程中仅有一个线程能执行,在该线程放弃CPU之前,其它线程只能等待。

  1. 组合方式

有些OS把用户级线程和内核支持线程两种方式进行组合,提供了组合方式ULT/KST线程。

  • 用户级线程和内核支持线程连接方式的不同,从而形成了三种不同的模型

The many-to-one model maps multiple user threads to a single kernel thread of control.
Advantages: better concurrency, one thread is blocked, allowing another thread to be scheduled for execution;
Disadvantages: high overhead; the number of threads in the entire system is limited;

One-to-one model For each user thread, a kernel control thread is connected to it.
Advantages: low overhead, high efficiency
Disadvantages: one thread blocks, the entire process blocks; multiple threads mapped to one core cannot use multiprocessors

The many-to-many model maps multiple user threads to multiple kernel threads of control.
Combining the advantages of the above two approaches

2.8.2 Implementation of threads

  1. The implementation of kernel support threads

In an OS where only kernel support threads are set, a possible thread control method is that when the system creates a new process, it allocates a task data area PTDA for it, including several thread control block TCB spaces

insert image description here

Figure 9. Task data area space
Whenever a process wants to create a thread, it allocates a TCB for the new thread, fills in the relevant information in the TCB, and allocates necessary resources for it, such as allocating hundreds to thousands of bytes of stack space and Local storage, so newly created threads are conditionally executed immediately. When all the TCB space in PTDA has been used up, and the process wants to create new threads, as long as the number of threads it creates does not exceed the allowed value of the system (usually tens to hundreds), the system can do it again Allocate new TCB space; when a thread is revoked, all resources and TCBs of the thread should also be reclaimed.

The creation and cancellation of threads supported by the kernel are similar to those of processes.

The scheduling and switching of threads supported by the kernel is very similar to the scheduling and switching of processes, and it is also divided into two types: preemptive and non-preemptive.

  1. Implementation of user-level threads
  • runtime system

The so-called "runtime system" is essentially a collection of functions (processes) for managing and controlling threads, including functions for creating and canceling threads, functions for thread synchronization and communication, and functions for implementing thread scheduling. It is because of these functions that user-level threads are independent of the kernel. All functions in the runtime system reside in user space and serve as an interface between user-level threads and the kernel.

  • kernel thread of control

This thread is also known as a lightweight process LWP. Each process can have multiple LWPs. Like user-level threads, each LWP has its own data structure (such as TCB), including thread identifiers, priorities, states, and stacks and local storage areas. . LWPs can also share resources owned by processes. LWP can obtain the services provided by the kernel through system calls, so that when a user-level thread is running, it only needs to be connected to an LWP, and then it has all the attributes of the kernel-supported thread. This thread implementation is the combination method .
insert image description here

Figure 10. Utilizing lightweight processes as intermediate systems

2.8.3 Thread Creation and Termination

  • Thread creation
    In a multi-threaded OS environment, when an application starts, usually only one thread is executing, and this thread is called an "initialization thread". It can create several threads as needed. When creating a new thread, it is necessary to use a thread creation function (or system call) and provide corresponding parameters, such as the entry pointer pointing to the thread main program, the size of the stack, and the priority used for scheduling. After the thread creation function is executed, a thread identifier is returned for later use.

  • thread termination

    When a thread has completed its task (work), or the thread has an abnormal situation during operation and must be forcibly terminated, the terminating thread executes the termination operation on it by calling the corresponding function (or system call). But some threads (mainly system threads), once they are established, they run forever without being terminated. In most os, the thread does not immediately release the resources it occupies after being terminated. Only when other threads in the process execute the separation function, the terminated thread is separated from the resources, and the resources at this time can be used by other resources. thread utilization.

There are two ways to terminate a thread: one is to exit voluntarily after the thread has finished its work; the other is to terminate the thread forcibly due to an error during operation or by other threads for some reason.


  • Reference: Computer Operating System (Fourth Edition) (Tang Xiaodan)

Guess you like

Origin blog.csdn.net/woschengxuyuan/article/details/126897479