Notas de estudio "Introducción al sistema operativo" (2): virtualización de la CPU (proceso)

Notas de estudio sobre "Introducción al sistema operativo" (1): Descripción general del sistema operativo

Proceso de creación del programa


Programa: una colección de instrucciones y datos, generalmente almacenados como un archivo de destino en el disco.
Proceso: la actividad de ejecución de un programa en un determinado conjunto de datos es la unidad básica de asignación y programación de recursos por parte del sistema.
El programa ejecutable se encuentra en el disco, y el programa estático debe cargarse en la memoria para generar un proceso dinámico antes de que la CPU pueda buscar y ejecutar continuamente instrucciones. El programa contiene principalmente código y datos estáticos en el disco duro y, por el contrario, el proceso parece tener más almacenamiento dinámico. No solo eso, cada proceso también tiene su propio bloque de control de proceso de tarjeta de identificación. ¿Cómo surgieron estos? Lo siguiente explicará uno por uno desde el espacio de direcciones virtuales.

Espacio de direcciones virtuales

Inserte la descripción de la imagen aquí
Memoria virtual: un método de administración de memoria. El sistema operativo divide y administra un espacio en el disco. Cuando la memoria física se agota, puede usarse como memoria física. La memoria virtual se puede asignar a la memoria física a través de una tabla de páginas.

Espacio de direcciones virtuales: en un sistema operativo multitarea, cada proceso se ejecuta en su propio entorno limitado de memoria, que es el espacio de direcciones virtuales (espacio de direcciones virtuales). El espacio de direcciones virtuales se compone de espacio de kernel (espacio de kernel) y espacio de usuario (espacio de usuario).
Inserte la descripción de la imagen aquí

2. Bloque de control de proceso

Cuando el sistema operativo crea un proceso, estará equipado con un bloque de control de proceso (PCB) en el espacio del núcleo, que
contiene una estructura de datos que describe el estado actual del proceso y toda la información sobre el proceso de gestión. El bloque de control de proceso en el sistema operativo Linux es en realidad una estructura task_struct, ubicada en sched.h, que se presenta brevemente a continuación.
Inserte la descripción de la imagen aquí
(1) Estado del proceso: el estado de ejecución común de un proceso incluye Listo, Bloqueado y En ejecución.

enum proc_state { READY, RUNNING, READY };

Inserte la descripción de la imagen aquí
Listo: el proceso tiene todos los recursos necesarios para ejecutarse, esperando asignar CPU.
En ejecución: el proceso se está ejecutando en la CPU, es decir, la CPU está ejecutando las instrucciones contenidas en el proceso.
Bloqueado / En espera: solicitudes de eventos distintos de la CPU (como las solicitudes de E / S) que se producen mientras el proceso se está ejecutando, lo que otorga derechos de uso de la CPU.
Tarea de simulación: transición de estado del proceso de simulación

(2) Identificador de proceso (número / identificador de proceso): un identificador único que describe este proceso, utilizado para distinguir otros procesos.

int pid;		// Process ID

(3) Contador de programa (contador de programa) e información de registro (registros): la dirección de entrada y la información que se guardará cuando se cambie el proceso

// the registers xv6 will save and restore
// to stop and subsequently restart a process
struct context {
  int eip;		// 程序计数器(PC),存放下一个CPU指令存放的内存地址
  int ebx;		// 基址寄存器, 在内存寻址时存放基地址
  int ecx;		// 计数器(counter),loop循环的内定计数器
  int edx;		// 用来放整数除法产生的余数
  int esi;		// 源变址寄存器
  int edi;		// 目的变址寄存器
  int esp;		// 栈指针寄存器
  int ebp;		// 基址指针寄存器
};

(4) Límites de memoria (límites de memoria)

char *mem;		// Start of process memory
uint sz;		// Size of process memory

(5) Abra la lista de archivos

struct file *ofile[NOFILE]; // Open files

(6) Puntero del proceso: los punteros se utilizan para vincular los bloques de control del proceso entre sí. La
Inserte la descripción de la imagen aquí
lista de procesos está organizada por el sistema configurando el puntero del encabezado de la cola lista, bloqueando el puntero del encabezado de la cola y ejecutando el puntero del encabezado de la cola, y cuelga el PCB del proceso de acuerdo con el estado del proceso Forme una cola después del puntero de cabecera correspondiente

3. Partición de espacio de usuario

El programa fuente contiene código y datos, y el archivo ejecutable generado por la vinculación se compila en forma de ensamblaje y se carga en la memoria como un archivo binario. El programa accede a los datos a través de variables, pero no existe un concepto de variables en binario, y solo se puede acceder a los datos a través de direcciones de memoria. Si se accede a todas las variables por dirección, esto es ineficiente y poco realista. Por lo tanto, es necesario particionar de acuerdo con la naturaleza de las diferentes variables. Por ejemplo, el contenido de las variables locales es corto y se debe acceder con frecuencia, pero el ciclo de vida es muy corto. Por lo general, solo sobrevive en un método, un área pequeña se divide específicamente de la memoria y la pila con nombre. ), Asignado y recuperado por el compilador, alta eficiencia. Otro ejemplo es que es posible que no sea necesario acceder a una estructura más grande con demasiada frecuencia, pero tiene un ciclo de vida largo. Por lo general, se usa en muchos métodos, y otra área grande se designa como un montón, que el programador asigna. Reciclar
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

4. Crear proceso

Inserte la descripción de la imagen aquí
Al crear un proceso, el sistema operativo genera un bloque de control de proceso (PCB) único para el proceso y lo cuelga en la cola del proceso. Se abre un espacio en la memoria para almacenar las variables y el código del programa, los parámetros de entrada se cargan en la pila argc/argv, el contenido del registro se borra y la main()dirección de entrada se envía al programa La PC del contador; la CPU ejecuta main()las instrucciones del programa y returnvuelve al sistema operativo cuando encuentra una instrucción; el sistema operativo libera el contenido del proceso y elimina el proceso de la cola de procesos.

Explique claramente cómo el programa se convierte en un proceso. Hablemos sobre cómo operar el proceso en la API de proceso.

Proceso de creación de interfaz de proceso API / C funciones de biblioteca

1. Crear un tenedor de proceso hijo ()

(1) Archivo de encabezado

#include <unistd.h>

(2) prototipo de función

#define int pid_t 
pid_t fork( void);

Valor de retorno: se devuelven dos valores después de una llamada exitosa, el proceso padre devuelve el PID del proceso hijo y el proceso hijo devuelve 0; -1 se devuelve si la llamada falla.

(3) Descripción de la función La
función principal main () creará automáticamente un proceso cuando se ejecute, llamado proceso padre; la llamada al sistema fork () se usa para crear un nuevo proceso, llamado proceso hijo. Al crear un proceso hijo, el proceso hijo tendrá su propio bloque de control de proceso (task_struct) en el núcleo, por lo que tendrá un PID diferente del proceso padre. Pero al mismo tiempo, el proceso secundario copia el resto del proceso primario (pila, segmento de código, etc.), y fork () se guarda como una llamada al sistema en la pila del proceso primario y el proceso secundario, por lo que regresará dos veces, dando como resultado dos valores de retorno.
Inserte la descripción de la imagen aquí

// p1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {			// 调用失败退出
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {	// 子进程内rc=0
        printf("hello, I am child (pid:%d)\n", (int) getpid());
    } else {				// 父进程内rc为子进程ID  getpid()为父进程ID
        printf("hello, I am parent of %d (pid:%d)\n", rc, (int) getpid());
    }
    return 0;
}

Inserte la descripción de la imagen aquí
El PID del proceso padre es 3838, y el PID del proceso hijo es 3827. Después de crear el proceso secundario, los dos procesos ejecutarán la siguiente instrucción después de la llamada al sistema fork (), por lo que no se generarán hello world, pero las dos líneas siguientes se pueden generar de acuerdo con diferentes valores de retorno de rc.

2. Bloquear el proceso actual wait ()

(1) Archivo de encabezado

#include <sys/wait.h>

(2) prototipo de función

#define int pid_t 
pid_t wait (int * status);

Parámetros: cuando el estado no es NULL, el estado del parámetro devolverá el valor de estado final del proceso secundario; si no le importa el estado final del proceso secundario, puede establecer el estado en NULL.
Valor de retorno: el PID del proceso hijo se devuelve si la ejecución es exitosa y -1 se devuelve si falla.

(3) Descripción de la función Cuando
no se utiliza wait (), el proceso padre y el proceso hijo se ejecutarán al mismo tiempo; después de usar wait (), el proceso padre esperará a que el proceso hijo se complete y regrese al PID del proceso hijo antes de ejecutarse.

// p2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {			// 调用失败退出
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {	// 子进程内rc=0
        printf("hello, I am child (pid:%d)\n", (int) getpid());
	    sleep(1);			// 等待一段时间再退出当前进程
    } else {				// wc为子进程PID
        int wc = wait(NULL);
        printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
	       rc, wc, (int) getpid());
    }
    return 0;
}

Inserte la descripción de la imagen aquí
El PID del proceso primario es 838 y el PID del proceso secundario es 841. El valor de retorno de wait () es wc = 841.

3. clúster de funciones Exec ()

(1) Archivo de encabezado

#include <unistd.h>

(2) El prototipo de la función
exec se refiere a un grupo de familias de funciones. No existe un exec específico (). Ahora elegimos execvp () como ejemplo.

int execvp(const char *file, char *const argv[]);

Parámetros: archivo es el nombre del archivo a ejecutar, argv [] es la lista de parámetros de entrada
Valor de retorno: la función no regresará si la ejecución es exitosa, y -1 será devuelta directamente si la ejecución falla

(3) Descripción de la
función El clúster de funciones exec () puede hacer que el proceso secundario elimine la similitud del contenido del proceso principal y ejecute un programa completamente diferente.

// p3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        printf("hello, I am child (pid:%d)\n", (int) getpid());
        char *myargs[3];			// strdup()字符串拷贝库函数
        myargs[0] = strdup("wc");   // 程序: "wc" (字符统计)
        myargs[1] = strdup("p3.c"); // 参数: 需要统计的文件
        myargs[2] = NULL;           // 命令行结束标志
        execvp(myargs[0], myargs);  // 统计行、单词、字节数
        printf("this shouldn't print out");
    } else {
        int wc = wait(NULL);
        printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
	       rc, wc, (int) getpid());
    }
    return 0;
}

Inserte la descripción de la imagen aquí
El proceso secundario vuelve a cargar el programa de estadísticas de caracteres, contando el recuento de líneas de p3.c, el recuento de 32palabras 123y el recuento de bytes 966.

4. ¿Cuál es el uso de la interfaz API?

En informática, Shell se conoce comúnmente como shell (se utiliza para distinguirlo de un núcleo) y se refiere al software (analizador de comandos) que proporciona una interfaz operativa para los usuarios, como cmd en Windows y bash en Unix. Cuando se abre el shell, el shell es equivalente al proceso padre. El shell puede aceptar comandos y luego usar fork () para crear un proceso hijo para ejecutar el comando. Una vez que se completa la ejecución, el proceso hijo vuelve al shell para aceptar el siguiente comando.
(1) La entrada de la consola wc p3.c > newfile.rtfcreará el p3.cnúmero de líneas, palabras y bytes contados por el proceso secundario en segundo plano y lo escribirá newfile.rtf.
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
(2) Al ingresar ./p4en la consola , el p4.cnúmero de líneas, palabras y bytes contados por el subproceso se creará en segundo plano , y luego se creará p4.outputy escribirá, y la entrada cat p4.outputpuede mostrar el contenido.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
		// 重定向输出到文件
		close(STDOUT_FILENO); 
		open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);

		// 重载"wc"程序
        char *myargs[3];			// strdup()字符串拷贝库函数
        myargs[0] = strdup("wc");   // 程序: "wc" (字符统计)
        myargs[1] = strdup("p4.c"); // 参数: 需要统计的文件
        myargs[2] = NULL;           // 命令行结束标志
        execvp(myargs[0], myargs);  // 统计行、单词、字节数
    } else {
        int wc = wait(NULL);
		assert(wc >= 0);
    }
    return 0;
}

Inserte la descripción de la imagen aquí
Tarea de código: uso de API de proceso

5. Comando del sistema, interfaz API y relación de llamada del sistema

Llamada del sistema: un conjunto de interfaces "especiales" que el sistema operativo proporciona para las llamadas de programas de usuario. Los programas de usuario pueden obtener servicios proporcionados por el núcleo del sistema operativo a través de este conjunto de interfaces "especiales". Por ejemplo, el usuario puede crear un proceso llamando a sys_fork () a través del sistema de proceso.

Interfaz de programación de aplicaciones (API): una interfaz de función que los programadores pueden usar directamente en el espacio del usuario. Es una función predefinida, como una función fork (), que proporciona una aplicación con la capacidad de acceder a un conjunto de llamadas al sistema.

Comando del sistema: el comando del sistema es una capa superior a la API. En realidad es un programa ejecutable. Hace referencia internamente a la interfaz de programación del usuario (API) para lograr la función correspondiente. El
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
proceso es el siguiente: utilice el comando del sistema para gcc -o p1 p1.c -Wall -Werrorllamar al compilador gcc para compilar Genere un programa ejecutable p1, luego use el comando del sistema para ./p1ejecutar el proceso de creación del programa, ejecute la función API en el proceso y encuentre el subproceso de creación de llamadas del sistema correspondiente al espacio del núcleo de fork()acuerdo con frok()el número de llamada del sistema sys_fork().

Notas de estudio "Introducción al sistema operativo" (3): virtualización de la CPU (mecanismo)

Publicado 21 artículos originales · elogiado 8 · visitas 1495

Supongo que te gusta

Origin blog.csdn.net/K_Xin/article/details/104636421
Recomendado
Clasificación