20191325学习笔记6

第三章 Unix/Linux进程管理

基本概念

1. 多任务处理

多任务处理指的是同时执行几个独立任务的能力,是通过在不同任务之间多路复用CPU的执行时间来实现。

多任务处理系统

多任务处理(MT)系统,说明多任务处理、上下文切换和进程处理原则。下面的程序实现了一个模拟操作系统内核模式各项操作的多任务环境,由以下几个部分组成。 1. type.h 文件 type.h 文件定义了系统常数和表示进程的简单 PROC结构体。

/*********** type.h file ************/
#define NPROC   9               // number of PROCs
#define SSIZE 1024               // gtack size = 4KB

// PROC status
#define FREE     0
#define READY   1
#define SLEEP   2
#define ZOMBIE   3

typedef struct proc{
struct proc *next;             // next proc pointer
int *ksp;                     // saved stack pointer
int pid;                       // pid = 0 to NPROC-1
int ppid;                     // parent pid
int status;                   // PROC status
int priority;                 // scheduling priority
int kstack[SSIE]               // process stack
}PROC;

2. ts.s文件 ts.s是汇编代码,在32位GCC汇编代码中可实现进程上下文切换。

#------------- ts.s file file -----------------
      .globl running, scheduler, tswitch
tswitch:
SAVE: pushl %eax
      pushl %ebx
      pushl %ecx
      pushl %edx
      pushl %ebp
      pushl %esi
      pushl %edi
      pushfl
      movl running, %ebx # ebx -> PROC
      movl %esp, 4(%ebx)   # PORC.save_sp = esp
FIND: call scheduler
RESUME:movl running, %ebx # ebx -> PROC
      movl 4(%ebx), %esp #esp = PROC.saved_sp
      popf1
      popl %edi
      popl %esi
      popl %ebp
      popl %edx
      popl %ecx
      popl %ebx
      popl %eax
      ret
# stack contents = |retpc|eax|ebx|ecx|edx|ebp|esi|edi|eflag|
#                   -1   -2 -3 -4 -5 -6 -7 -8   -9

3. queue.c文件 queue.c文件可实现队列和链表操作函数。enqueue()函数按优先级将PROC输入队列中。在优先级队列中,具有相同优先级的进程按先进先出(FIFO)的顺序排序。dequeue()函数可返回从队列或链表中删除的第一个元素。printList()函数可打印链表元素。

/******************************* queue.c file *******************************/
int enqueue(PROC **queue,PROC *p)
{
  PROC *q = *queue;
  if(q == 0 || p->priority> q->priority){
      *queue = p;
      p->next = q;
  }
  else{
      while(g->next && p->priority <= q->next->priority)
          q = q->next;
      p->next = q->next;
      q->next = p;
  }
}
PROC *dequeue (PROC **queue)
{
  PROC *p = *queue;
  if (p)
      *queue =(*queue)->next;
  return p;
}
int printList(char *name,PROC *p)
{
  printf("%s = ",name);
  while(p){
      printf("[8d %d]->",p->pid,p->priority);
      p = p->next;
  }
  printf("NULL ");
}

4. t.c文件 t.c文件定义MT系统数据结构、系统初始化代码和进程管理函数。

2. 进程的概念

操作系统是一个多任务处理系统。在操作系统中,任务也称为进程。在实际应用中,任务和进程这两个术语可以互换使用。在第2章中,我们把执行映像定义为包含执行代码、数据和堆栈的存储区。进程的正式定义∶进程是对映像的执行。 操作系统内核将一系列执行视为使用系统资源的单一实体。系统资源包括内存空间、I/O设备以及最重要的 CPU时间。在操作系统内核中,每个进程用一个独特的数据结构表示,叫作进程控制块(PCB)或任务控制块(TCB)等。在本书中,我们直接称它为PROC 结构体。与包含某个人所有信息的个人记录一样,PROC结构体包含某个进程的所有信息。在实际操作系统中,PROC结构体可能包含许多字段,而且数量可能很庞大。首先,我们来定义一个非常简单的PROC结构体来表示进程。

PROC定义:Linux系统上的/proc目录是一种文件系统,即proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

typedef etruct proc(
struct proc *next;       // next proc pointer
  //指向下一个PROC结构体的指针
int *ksp;               // saved sp: at byte
  //保存的堆栈指针
offset 4
int pid;                 // process ID
  //标识一个进程的进程ID编号
int ppid;               // parent proces pid
  //父进程 ID 编号
int statuS;             // PROC
  //进程的当前状态
status=FREE|READY, etc.
int priority;           // scheduling priority
    //进程调度优先级
int kstack[1024];       // process execution
  //进程执行时的堆栈
stack
)PROC;

在PROC结构体中

next是指向下一个PROC结构体的指针,用于在各种动态数据结构(如链表和队列)中维护PROC结构体。

ksp字段是保存的堆栈指针。当某进程放弃使用CPU时,它会将执行上下文保存在堆栈中,并将堆栈指针保存在PROC.ksp中,以便以后恢复。

pid是标识一个进程的进程ID编号。

ppid是父进程 ID 编号。

status是进程的当前状态。

priority是进程调度优先级。

kstack 是进程执行时的堆栈。

操作系统内核通常会在其数据区中定义有限数量的 PROC结构体,表示为∶ PROC proc [NPROC]; // NPROC a constant,e.g.64 用来表示系统中的进程。在一个单 CPU系统中,一次只能执行一个进程。操作系统内核通常会使用正在运行的或当前的全局变量PROC指针,指向当前正在执行的 PROC。在有多个CPU的多处理器操作系统中,可在不同CPU上实时、并行执行多个进程。因此,在一个多处理器系统中正在运行的[NCPU]可能是一个指针数组,每个指针指向一个正在特定CPU上运行的进程。

进程同步

一个操作系统包含许多并发进程,这些进程可以彼此交互。进程同步是指控制和协调进程交互以确保其正确执行所需的各项规则和机制。最简单的进程同步工具是休眠和唤醒操作。 1. 睡眠模式 有时候,进程需要等待直到某个特定的事件发生,例如设备初始化完成、I/O 操作完成或定时器到时等。 在这种情况下,进程则必须从运行队列移出,加入到一个等待队列中,这个时候进程就进入了睡眠状态。 为实现休眠操作,我们可以在 PROC结构体中添加一个event字段,并实现ksleep(int event)函数,使进程进入休眠状态。

进程睡眠状态有两种:

一种是可中断的睡眠状态,其状态标志位TASK_INTERRUPTIBLE 另一种是不可中断的睡眠状态,其状态标志位为TASK_UNINTERRUPTIBLE

2. 唤醒操作 多个进程可能会进入休眠状态等待同一个事件。在这种情况下,所有这些进程都将休眠等待同一个事件值。当某个等待时间发生时,另一个执行实体(可能是某个进程或中断处理程序)将会调用kwakeup(event),唤醒正处于休眠状态等待该事件值的所有程序。如果没有任何程序休眠等待该程序,kwakeup()就不工作,即不执行任何操作。

进程终止

在以下种情况下,当进程终止时,最终都会在操作系统内核中调用 kexit() 。 1. 正常终止 进程调用 exit(value), 发出_exit(value)系统调用来执行在操作系统内核中的kexit(value) 2. 异常终止 进程因某个信号而异常终止。

 

3、I/O重定向

(1)文件流和文件描述符

每个文件流都是指向执行映像堆区中FILE结构体的一个指针。每个文件流对应Linux内核中的一个打开文件。每个打开文件都用一个文件描述符(数字)表示。

(2)文件流I/O和系统调用

当进程执行库函数

scanf("%s",&item);

它会试图从stdin文件输入一个(字符串)项,指向FILE结构体。如果FILE结构体的fbuf[]

4.管道

管道是用于进程交换数据的单向进程件通信通道。管道有一个读取端和一个写入端。

管道命令处理 在Unix/Linux中,命令行 cmd1 | cmd2 , sh将通过一个进程运行cmd1,并通过另一个进程运行cmd2,他们通过一个管道连接在一起,因此cmd1的输出变为cmd2的输入

命令管道 命令管道又叫FIFO 在sh中,通过mknod命令创建一个命令管道:mknod mypipe p 或在c语言中发出mknod()系统调用int r = mknod("mypipe",s_IFIFP,0); 进程可像访问普通文件一样发个文命名管道。

6、Unix/Linux中的进程

1、进程来源

强行创建PID=0初始进程—>系统执行初始进程P0—>挂载一个跟文件系统—>P0复刻出一个子进程P1

2、INIT和守护进程

3、登陆进程

4、sh进程

当用户成功登录时,LOGIN进程会获取用户的gid和uid,从而称为用户的进程。他将目录更改为用户的主目录并执行列出的程序,通常是命令解释程序sh。

5、进程的执行模式

在Unix/Linux中进程以两种不同的模式执行,即内核模式和用户模式

img

一旦进入Umode就不能随意更改CPU的状态。

 

7、实践

fork()演示

 

env命令 用于显示系统中已存在的环境变量,以及在定义的环境中执行指令。该命令只使用”-“作为参数选项时,隐藏了选项”-i”的功能。若没有设置任何选项和参数时,则直接显示当前的环境变量。

如果使用env命令在新环境中执行指令时,会因为没有定义环境变量”PATH”而提示错误信息”such file or directory”。此时,用户可以重新定义一个新的”PATH”或者使用绝对路径。

详见:http://ipcmen.com/env

原文地址:https://www.cnblogs.com/2902480848sy/p/15451906.html