[Linux] Concepto de proceso

[Linux] Concepto de proceso

definición del proceso

Un proceso es una instancia de ejecución de un programa y una entidad responsable de asignar los recursos del sistema (tiempo de CPU, memoria).

La relación entre proceso y programa.

El programa binario compilado formado por el código escrito en el lenguaje de programación se almacenará en el disco duro. Cuando la computadora inicia un programa, el código y los datos relevantes del programa se cargarán en la memoria para que los use la CPU:

imagen-20230803184610548

Después de que el código del programa y los datos se cargan en la memoria, el sistema operativo debe administrar el programa. Para administrar mejor estos programas, primero es necesario crear las estructuras correspondientes para describir estos programas. En el sistema operativo, se utiliza para describe la estructura del programa . Se llama Bloque de control de procesos (PCB para abreviar). La PCB en el sistema Linux se llama task_struct . La dirección del código y los datos correspondientes también se registrarán en la PCB. Para poder acceder mejor a estos PCB, se utiliza una estructura de cadena para organizarlos.:

imagen-20230803185254037

El contenido de task_struct se clasifica de la siguiente manera:

  • Identificador: un identificador único que describe este proceso y se utiliza para distinguir otros procesos.
  • Estado: Estado de la tarea, código de salida, señal de salida, etc.
  • Prioridad: Prioridad relativa a otros procesos.
  • Contador de programa: la dirección de la siguiente instrucción que se ejecutará en el programa.
  • Punteros de memoria: incluidos punteros a código de programa y datos relacionados con procesos, así como punteros a bloques de memoria compartidos con otros procesos.
  • Datos de contexto: Los datos en los registros del procesador cuando se ejecuta el proceso [ejemplo de licencia, agregue la figura de CPU, registros].
  • Información de estado de E/S: incluye solicitudes de E/S mostradas, dispositivos de E/S asignados al proceso y una lista de archivos utilizados por el proceso.
  • Información contable: puede incluir el tiempo total del procesador, el número total de relojes utilizados, límites de tiempo, cuentas contables, etc.
  • otra información.

Si simplemente carga el código y los datos del programa en la memoria, pero el sistema operativo no crea una PCB para su administración, el sistema operativo no lo programará y no podrá completar la ejecución del programa. , la esencia del proceso es el código y los datos en la memoria . Datos + bloque de control de proceso . Con la PCB, el sistema operativo transforma la gestión del proceso en la gestión de la PCB. Por ejemplo, si desea cerrar un proceso, borre su PCB y luego la memoria correspondiente borrará su memoria Código y datos:

imagen-20230803190524985

Verifique el proceso en Linux

Para ver mejor el proceso en el sistema operativo Linux, cree el archivo fuente myprocess.c y el archivo makefile para crear el programa binario.

El contenido del archivo fuente es el siguiente:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  while(1)
  {
    
    
    printf("hello myprocess\n");
    sleep(1);
  }
  return 0;
}

El contenido del archivo MAKE es el siguiente:

myprocess:myprocess.c
	gcc -o myprocess myprocess.c
.PHONY:clean
clean:
	rm -f myprocess

Cree los archivos anteriores y compílelos para obtener un programa binario llamado myprocess, luego inicie dos clientes en Linux y uno de los programas de inicio se convierte en un proceso:

imagen-20230803193450976

Ingrese otro cliente ps axj | head -1 && ps axj | grep myprocess | grep -v greppara ver el proceso de myprocess:

imagen-20230803193707725

Lo anterior es el uso de instrucciones para ver el proceso, las instrucciones son las siguientes:

ps axj | head -1 && ps axj | grep 进程名 | grep -v 进程名

Además, también puedes ver el proceso en el directorio /proc:

imagen-20230803193931708

El directorio /proc es un directorio a nivel de memoria que no existe en el disco duro. Habrá un directorio llamado igual que pid. La task_struct del proceso correspondiente se registrará en este directorio. Si el proceso cierra el directorio correspondiente , será eliminado.

Obtener el identificador del proceso mediante una llamada al sistema en Linux

Para identificar de forma única un proceso, el sistema operativo Linux establece un identificador de proceso en la PCB para cada proceso, que es pid. También proporciona la función de interfaz del sistema getpid para obtener el pid del proceso actual, su introducción es la siguiente:

imagen-20230803195336806

Para probar la función getpid, modifique el archivo fuente myprocess.c, el contenido es el siguiente:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    
    
  while(1)
  {
    
    
    printf("hello myprocess, 我的pid是%d\n", getpid());
    sleep(1);
  }
  return 0;
}

Utilice el comando para consultar el pid del proceso y ver los resultados de la ejecución del proceso:

imagen-20230803195628555

Además, el sistema operativo Linux también establece un identificador de proceso principal, que se utiliza para registrar el pid del proceso principal del proceso actual, es decir, ppid, y también proporciona la función getppid para obtener el ppid del proceso actual. de ppid es el siguiente:

imagen-20230803200016344

Para probar la función getppid, modifique el archivo fuente myprocess.c de la siguiente manera:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    
    
  while(1)
  {
    
    
    printf("hello myprocess, 我的pid是%d, 我的ppid为%d\n", getpid(), getppid());
    sleep(1);
  }
  return 0;
}

Utilice el comando para consultar el pid del proceso y ver los resultados de la ejecución del proceso:

imagen-20230803201344196

Aprovecha para cerrar el proceso varias veces ctrl+cy luego reiniciarlo:

imagen-20230803201448298

Se puede ver que no importa cómo cambie el pid del proceso, el pid del proceso no cambiará. Intentamos usar el comando para ver el proceso padre:

imagen-20230803201620342

De hecho, este proceso padre es bash. A través del fenómeno anterior, podemos sacar las siguientes conclusiones:

  • El intérprete de línea de comando (bash) es esencialmente un proceso.
  • Todos los programas iniciados desde la línea de comando eventualmente se convertirán en procesos, y el proceso principal correspondiente de este proceso es bash.

Cree un proceso mediante llamadas al sistema en Linux: uso de la función fork

La función fork es una llamada al sistema proporcionada por el sistema Linux para crear un proceso hijo.

  • Después de que la función fork se ejecute correctamente, el flujo de ejecución se convertirá en dos, uno es el proceso principal que llama a la función fork y el otro es el proceso hijo creado por la función fork.
  • El proceso hijo creado compartirá el código y los datos del proceso padre con el proceso padre, y el proceso hijo ejecutará el código después de que la función de bifurcación del proceso padre cree el proceso hijo.
  • La función fork devuelve el pid del proceso hijo al proceso padre, 0 al proceso hijo creado y -1 en caso de error.

Para probar la función fork, modifique el archivo fuente myprocess.c con el siguiente contenido:

#include <stdio.h>
#include <assert.h>
#include <unistd.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    printf("我是子进程,我的pid是%d, 我的ppid是%d\n", getpid(), getppid());
    sleep(2);
  }
  else if (id > 0)
  {
    
    
    //父进程
    printf("我是父进程,我的pid是%d, 我的ppid是%d\n", getpid(), getppid());
    sleep(3);
  }
  else 
  {
    
    
    //fork函数出错
    assert(1);
  }
  return 0;
}

ilustrar:

  • Los archivos de encabezado requeridos por la función fork son unistd.h.
  • Utilice juicio condicional para controlar los procesos padre e hijo para ejecutar códigos diferentes.

Utilice comandos para consultar procesos y ver los resultados de la ejecución del proceso:

imagen-20230804105943957

El principio de la función de horquilla.

La esencia de un proceso es PCB + código y datos en la memoria. Dado que el proceso hijo creado por la función fork comparte código y datos con el proceso padre, el principio de crear un proceso hijo mediante la función fork es crear una PCB para el proceso hijo La mayor parte de la PCB Los datos son los mismos que los del proceso padre y apuntan al mismo código y datos:

imagen-20230804113115080

La encarnación de la independencia del proceso en fork.

Primero, se da el siguiente teorema: los procesos son independientes entre sí y cualquier operación de un proceso no afectará a otros procesos.

La independencia entre procesos también se puede garantizar cuando se utiliza la función fork para crear procesos secundarios. Para verificar la independencia, modifique el archivo fuente myprocess.c con el siguiente contenido:

#include <stdio.h>
#include <assert.h>
#include <unistd.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    printf("我是子进程,我的pid是%d, 我的ppid是%d\n", getpid(), getppid());
    sleep(20);
    printf("我是子进程,我的pid是%d, 我的ppid是%d\n", getpid(), getppid());
    printf("我是子进程,我已经关闭了\n");
  }
  else if (id > 0)
  {
    
    
    //父进程
    printf("我是父进程,我的pid是%d, 我的ppid是%d\n", getpid(), getppid());
    sleep(3);
    printf("我是父进程,我已经关闭了\n");
  }
  else 
  {
    
    
    //fork函数出错
    assert(1);
  }
  return 0;
}

Utilice comandos para consultar procesos y ver los resultados de la ejecución del proceso:

Al principio, los procesos padre e hijo se ejecutan juntos:

imagen-20230804114253740

El proceso principal se cierra y el proceso secundario se ejecuta normalmente:

imagen-20230804114347222

Finalmente se cierra el proceso hijo:

imagen-20230804114411668

De las pruebas anteriores se puede ver que el cierre del proceso principal no afecta la ejecución normal del proceso secundario, lo que garantiza un cierto grado de independencia. Además, debido a que el código es de solo lectura, el proceso principal no puede afectar al proceso secundario modificando el código, y las modificaciones de datos activarán el mecanismo de copia en escritura , lo que garantiza un cierto grado de independencia.

Para observar el fenómeno de copia en escritura, modifique el archivo fuente myprocess.c de la siguiente manera:

#include <stdio.h>
#include <assert.h>
#include <unistd.h>

int main()
{
    
    
  int a = 0;
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    printf("我是子进程,我的pid是%d, 我的ppid是%d, a:%d, &a:%p\n", getpid(), getppid(), a, &a);
    sleep(5);
    printf("我是子进程,我的pid是%d, 我的ppid是%d, a:%d, &a:%p\n", getpid(), getppid(), a, &a);
  }
  else if (id > 0)
  {
    
    
    //父进程
    printf("我是父进程,我的pid是%d, 我的ppid是%d, a:%d, &a:%p\n", getpid(), getppid(), a, &a);
    a = 666;
    printf("我是父进程,我的pid是%d, 我的ppid是%d, a:%d, &a:%p\n", getpid(), getppid(), a, &a);
    sleep(3);
    printf("我是父进程,我已经关闭\n");
  }
  else 
  {
    
    
    //fork函数出错
    assert(1);
  }
  return 0;
}

Ver los resultados de la ejecución del proceso:

imagen-20230804120919703

Al observar el fenómeno, podemos encontrar que después de que el proceso padre modifica el valor de a, el valor de a del proceso hijo no cambia, pero las direcciones de la variable a del proceso padre y del proceso hijo son las mismas. es un fenómeno causado por la copia en escritura.

El principio de la función fork que devuelve dos valores de retorno

Dado que el proceso hijo creado por fork comparte código y datos con el proceso padre, y la función fork también es parte del código del proceso padre, una vez que el proceso padre completa la creación del proceso hijo, el proceso hijo también ejecutará el función fork para crear el código restante del proceso hijo. Esto incluye la parte de retorno de la función fork, por lo que el proceso padre ejecuta la parte de retorno, y el proceso hijo también ejecuta la parte de retorno, lo que hace que la función fork devuelva dos valores de retorno :

imagen-20230804121340511

Supongo que te gusta

Origin blog.csdn.net/csdn_myhome/article/details/132458330
Recomendado
Clasificación