Programación de procesos Linux

  
 

Sistema operativo
Para implementar múltiples procesos, la programación de procesos es esencial. ¿Qué tan importante es el proceso de programación? Primero, debemos ser claros: la programación del proceso es programar el proceso en el estado TASK_RUNNING. Si el proceso es inejecutable (inactivo o de otro tipo), tiene poco que ver con la programación del proceso. El kernel de Linux divide los procesos en dos niveles: procesos normales y procesos en tiempo real. Los procesos en tiempo real tienen mayor prioridad que los procesos normales y sus estrategias de programación son diferentes.
1.1 Programación de procesos en tiempo real
Proceso en tiempo real en tiempo real, el significado original es "la operación dada debe completarse dentro de un cierto tiempo". El punto no es que la operación deba manejarse tan rápido, sino que el tiempo es controlable (en el peor de los casos, no puede atravesar el tiempo dado). Este "tiempo real" se denomina "tiempo real difícil" y se utiliza en sistemas muy sofisticados (como cohetes, misiles, etc.). En general, los sistemas duros en tiempo real son relativamente especializados.
El sistema operativo de propósito general como Linux, obviamente, no puede cumplir con estos requisitos. La existencia de procesamiento de interrupciones, memoria virtual y otros mecanismos genera una gran incertidumbre en el tiempo de procesamiento. Los cachés de hardware, las búsquedas de disco y la contención de bus también pueden generar incertidumbre. Linux pretende implementar el sistema operativo de propósito general "en tiempo real", de hecho, solo implementa "tiempo real flexible", es decir, para satisfacer las necesidades del proceso en tiempo real tanto como sea posible.
Si un proceso tiene requisitos de tiempo real (es un proceso en tiempo real), siempre que sea ejecutable, el kernel lo mantiene en ejecución para satisfacer sus necesidades de CPU tanto como sea posible hasta que esté listo. La cosa entonces duerme o se cierra (se vuelve no ejecutable). Si hay varios procesos en tiempo real en el estado ejecutable, el kernel satisfará primero la CPU del proceso en tiempo real de mayor prioridad hasta que deje de ser ejecutable. Por lo tanto, mientras el proceso en tiempo real de alta prioridad esté siempre en el estado ejecutable, el proceso en tiempo real de baja prioridad no podrá obtener la CPU, mientras que el proceso en tiempo real siempre esté en el estado ejecutable, el proceso normal no podrá obtener la CPU.
(Más tarde, el kernel agregó /proc /sys /kernel /sched_rt_runtime_us y /proc /sys /kernel /sched_rt_period_us dos parámetros, limitando el proceso en tiempo real para ejecutar sched_rt_runtime_us durante tanto tiempo en el período de sched_rt_period_us. Si siempre hay un proceso en tiempo real en un estado ejecutable, déle al proceso normal una pequeña posibilidad de ejecución. Por lo tanto, si hay varios procesos en tiempo real de la misma prioridad en un estado ejecutable, entonces hay dos Hay una estrategia de programación disponible:
l SCHED_FIFO
Primero en entrar, primero en salir. Hasta que el primer proceso ejecutado no sea ejecutable, los procesos subsiguientes están programados para ejecutarse. Bajo esta estrategia, el primer proceso Puede ejecutar la llamada al sistema sched_yield, renunciar voluntariamente a la CPU para dar energía a los procesos subsiguientes;
l SCHED_RR:
Rotación de la programación. El kernel asigna segmentos de tiempo para procesos en tiempo real, y permite que se utilice el siguiente proceso cuando se agote el período de tiempo. La diferencia entre la CPU y el FIFO es que se utiliza el intervalo de tiempo; en linux, el programa del usuario se puede configurar mediante la llamada al sistema sched_setscheduler. La política de programación y los parámetros de programación relacionados; la llamada al sistema sched_setparam solo se usa para establecer los parámetros de programación. Estas dos llamadas al sistema requieren que el proceso del usuario tenga la capacidad de establecer la prioridad del proceso (CAP_SYS_NICE, generalmente requiere privilegios de raíz) al establecer la política del proceso Para SCHED_FIFO o SCHED_RR, el proceso se convierte en un proceso en tiempo real, y la prioridad del proceso se especifica mediante la configuración de los parámetros de programación a través de las dos llamadas al sistema. Para los procesos en tiempo real, el núcleo no intenta ajustar su prioridad. Estas preguntas están relacionadas con el escenario de aplicación del programa del usuario. Solo el usuario puede responder, el kernel no puede ser interrumpido. En resumen, la programación de los procesos en tiempo real es muy simple. La prioridad del proceso y la estrategia de programación son todas El usuario está muerto, el kernel solo necesita seleccionar siempre el proceso de mayor prioridad en tiempo real para programar la ejecución. El único problema es que al seleccionar procesos en tiempo real con la misma prioridad, se deben considerar dos estrategias de programación. 1.2 Programación de procesos ordinarios
La idea central de la programación de procesos en tiempo real es Deje que el proceso en tiempo real de mayor prioridad en el estado ejecutable ocupe la CPU tanto como sea posible porque tiene requisitos en tiempo real, mientras que el proceso normal se considera un proceso sin requisitos en tiempo real, por lo que el programador intenta hacer que cada uno de los estados ejecutables El proceso comparte la CPU en una convivencia pacífica, por lo que los usuarios sienten que estos procesos se ejecutan al mismo tiempo. La programación de procesos ordinarios es mucho más complicada que los procesos en tiempo real. El núcleo debe considerar dos problemas: (1) ajustar dinámicamente la prioridad del proceso De acuerdo con las características de comportamiento del proceso, el proceso se puede dividir en "proceso interactivo" y "proceso por lotes": la tarea principal de los procesos interactivos (como programas de escritorio, servidores, etc.) es interactuar con el mundo exterior. Dichos procesos deberían tener una prioridad más alta y siempre duermen y esperan la entrada del mundo exterior. Cuando llega la entrada y el kernel se activa, deben programarse para que se ejecuten rápidamente para responder. Por ejemplo, si un programa de escritorio no responde después de medio segundo clic con el mouse, el usuario sentirá la "tarjeta" del sistema; la tarea principal del proceso por lotes (como el compilador) es realizar operaciones continuas, por lo que continuarán en Estado ejecutable. Por lo general, este proceso no requiere una alta prioridad. Por ejemplo, el compilador se ejecuta durante unos segundos y el usuario no se preocupará demasiado. Si el usuario puede saber claramente qué prioridad debe tener el proceso, puede usar las llamadas del sistema nice y setpriority para establecer prioridades. Ajustes de nivel. Sin embargo, las aplicaciones no son necesariamente tan típicas como los programas de escritorio y los compiladores. El comportamiento de un programa puede variar, y puede ser como un proceso interactivo por un tiempo y un proceso por lotes por un tiempo. Es difícil para el usuario establecer una prioridad adecuada para él. Por lo tanto, al final, la tarea de distinguir entre procesos interactivos y procesos por lotes recae en el programador del kernel. El programador se centra en el rendimiento del proceso durante un período de tiempo (principalmente, verifica su tiempo de suspensión y el tiempo de ejecución). Según algunas fórmulas empíricas, ¿se juzga si es interactivo o por lotes? ¿Cuál es el alcance? Finalmente decidió hacer algunos ajustes a su prioridad. Después de ajustar dinámicamente la prioridad del proceso, aparecen dos prioridades: a. La prioridad establecida por el programa del usuario (o el valor predeterminado, si no se establece), denominada prioridad estática. Este es el punto de referencia de la prioridad del proceso. A menudo, no se cambia durante el proceso de ejecución del proceso. B) Después de que la prioridad se ajusta dinámicamente, la prioridad real se denomina prioridad dinámica. Es probable que este valor cambie todo el tiempo.
(2) Equidad en la programación En un sistema que admite múltiples procesos, idealmente, cada proceso debería ocupar bastante la CPU de acuerdo con su prioridad. Y no parecerá que "quién tiene suerte, quién es mucho más" es una situación tan incontrolable. La programación justa de Linux es básicamente dos tipos de ideas: a. Al asignar segmentos de tiempo al proceso en el estado ejecutable (según la prioridad), el proceso que se está quedando fuera del período de tiempo se coloca en la cola de caducidad. Los procesos, como el estado ejecutable, han caducado y los intervalos de tiempo se reasignan, b. Ajusta dinámicamente la prioridad del proceso. A medida que el proceso se ejecuta en la CPU, su prioridad se reduce continuamente para que otros procesos de menor prioridad tengan la oportunidad de ejecutarse; esta última forma tiene una granularidad de programación más pequeña y será "equidad" &<; Priorización dinámica y " Se combinan dos cosas para simplificar enormemente el código del programador del núcleo. Por lo tanto, este método se ha convertido en el nuevo favorito del programador del kernel. Enfatice que los dos puntos anteriores son solo para procesos ordinarios. Para los procesos en tiempo real, el kernel no puede ajustar dinámicamente la prioridad y no tiene imparcialidad.
1.3 La eficiencia del programador
" Prioridad > Está claro qué proceso debe programarse para ejecutarse, y el programador también debe preocuparse por los problemas de eficiencia. El programador se ejecuta tantas veces como muchos otros procesos en el kernel. Si la eficiencia no es buena, perderá mucho tiempo de CPU y hará que el rendimiento del sistema disminuya. En Linux 2.4, el proceso de estado ejecutable se cuelga en una lista enlazada. Para cada programa, el programador necesita escanear la lista de enlaces completa para encontrar la óptima para ejecutar. La complejidad es O (n); en los primeros días de Linux 2.6, el proceso de estado ejecutable se colgó en N (N = 140) listas vinculadas, cada lista vinculada representa una prioridad y cuántas prioridades se admiten en el sistema. Lista enlazada Para cada programa, el programador solo necesita tomar el proceso al principio de la lista de la primera lista que no esté vacía. Esto mejora enormemente la eficiencia del programador, la complejidad es O (1); en la versión reciente de Linux 2.6, el proceso de estado ejecutable se cuelga en un árbol rojo-negro (concebible como un árbol binario equilibrado) en orden de prioridad. . Para cada programación, el programador debe encontrar el proceso de mayor prioridad en el árbol. La complejidad es O (logN). Entonces, ¿por qué desde la versión anterior de Linux 2.6 a la reciente versión de Linux 2.6, la complejidad del proceso de selección del programador ha aumentado? Esto se debe a que, al mismo tiempo, la implementación de equidad del programador cambia de la primera idea mencionada anteriormente a la segunda (ajustando dinámicamente la prioridad). El algoritmo O (1) se implementa en base a un pequeño número de listas vinculadas. Según mi entendimiento, esto hace que el rango de valores de prioridad sea pequeño (la discriminación es muy baja) y no cumple con los requisitos de imparcialidad. El uso de árboles rojo-negro no tiene límite en el valor de prioridad (se pueden usar 32 bits, 64 bits o más bits para indicar el valor de la prioridad), y la complejidad de O (logN) sigue siendo muy eficiente.
1.4 Tiempo de activación de la programación
El inicio de la programación tiene principalmente las siguientes situaciones: (1) El estado del proceso actual (el proceso que se ejecuta en la CPU) se convierte en no ejecutable. La llamada al sistema de ejecución de procesos se convierte activamente en no ejecutable. Por ejemplo, la implementación de nanosleep se pone en suspensión, realiza la salida de salida, etc. Los recursos solicitados por el proceso no se satisfacen y se ven obligados a ir a la suspensión. Por ejemplo, cuando se ejecuta la llamada del sistema de lectura, la memoria caché del disco no tiene los datos necesarios, por lo que el modo de espera espera la E /S del disco, el proceso responde a la señal y se vuelve no ejecutable. Por ejemplo, respondiendo a SIGSTOP en un estado de pausa, respondiendo a una salida SIGKILL, etc .; (2) preferencia. Cuando se ejecuta el proceso, no se pretende privarlo de los derechos de uso de la CPU. Esto se divide en dos situaciones: el proceso se queda sin intervalos de tiempo, o se produce un proceso de mayor prioridad.
1.5 Otros problemas
l Equilibrio de carga bajo múltiples procesadores
Bajo Linux, cada CPU tiene una cola ejecutable correspondiente, y un proceso de estado ejecutable solo puede estar en uno al mismo tiempo. Cola de ejecución.
Por lo tanto, " balanceo de carga multiprocesador " este problema está llegando. El kernel debe prestar atención al número de procesos en cada cola ejecutable de la CPU y realizar los ajustes apropiados cuando el número no está equilibrado. Cuándo ajustar, cuánto ajustar el proceso, estos son los requisitos del núcleo para cuidarlos. Por supuesto, trate de no ajustar lo mejor. Después de todo, toma la CPU y bloquea la cola ejecutable. El costo todavía es pequeño. Además, el núcleo tiene que preocuparse por la relación de cada CPU. La relación entre las dos CPU, que pueden ser independientes entre sí, pueden ser cachés compartidas, o incluso virtualizadas por la misma CPU física a través de la tecnología de subprocesamiento, también es una base importante para el equilibrio de carga. Cuanto más estrecha sea la relación, menos costoso será el proceso entre ellos.
l Herencia prioritaria
Debido a la exclusión mutua, un proceso (establecido en A) puede suspenderse porque espera para ingresar a la sección crítica. El proceso A se despierta hasta que el proceso que ocupa el recurso correspondiente (establecido en B) sale de la sección crítica. Puede haber situaciones en las que A tenga una prioridad muy alta y B tenga una prioridad muy baja. B ingresa a la sección crítica, pero está precedido por otros procesos de mayor prioridad (establecidos en C) y no puede salir de la sección crítica. Entonces A no puede ser despertado. A tiene una prioridad alta, pero ahora ha caído a B y ha sido reemplazado por C, que no tiene una prioridad demasiado alta, lo que hace que la ejecución se posponga. Este fenómeno se llama inversión de prioridad. Este fenómeno es muy irrazonable. Una mejor contramedida es: cuando A comienza a esperar a que B salga de la sección crítica, B obtiene temporalmente la prioridad de A (o supone que A tiene una prioridad más alta que B) para completar con éxito el procesamiento y salir de la sección crítica. Después de que se restablezca la prioridad de B Este es el método de la herencia de prioridad. Para lograr una herencia prioritaria, el núcleo tiene que hacer muchas cosas.
l Subprocesamiento de procesamiento de subprocesos

En Linux, el controlador de interrupciones se ejecuta en un contexto no programable. Desde la respuesta de la CPU, la interrupción de hardware salta automáticamente al controlador de interrupciones establecido por el núcleo para ejecutarse, hasta que el controlador de interrupciones finalice, no se puede anticipar el proceso completo. Si se anticipa un proceso, se puede reanudar más tarde mediante la información almacenada en su bloque de control de proceso (task_struct). El contexto de interrupción no tiene task_struct, y no puede ser recuperado si se le da prioridad. El manejador de interrupciones no puede ser reemplazado, lo que significa que la "prioridad" del manejador de interrupciones es mayor que cualquier proceso (debe esperar a que el manejador de interrupciones se complete antes de poder ejecutar el proceso). Sin embargo, en los escenarios de aplicaciones reales, puede ser que algunos procesos en tiempo real reciban una mayor prioridad que los controladores de interrupción. Por lo tanto, algunos sistemas con mayores requisitos de tiempo real otorgan al manejador de tareas una tarea de construcción y prioridad para que puedan ser reemplazados por procesos de alta prioridad cuando sea necesario. Pero obviamente, hacer este trabajo causará una sobrecarga al sistema, lo que también es una concesión al rendimiento para lograr el "tiempo real".

Copyright © Conocimiento de Windows All Rights Reserved