Estoy leyendo este libro , Programación avanzada de Linux por Mark Mitchell, Jeffrey Oldham y Alex Samuel. Es de 2001, un poco viejo. Pero me parece bastante bueno de todos modos.
Sin embargo, llegué a un punto en el que diverge de lo que mi Linux produce en la salida del shell. En la página 92 (116 en el visor), el capítulo 4.5 Implementación de subprocesos GNU / Linux comienza con el párrafo que contiene esta declaración:
La implementación de hilos POSIX en GNU / Linux difiere de la implementación de hilos en muchos otros sistemas similares a UNIX de una manera importante: en GNU / Linux, los hilos se implementan como procesos.
Esto parece un punto clave y luego se ilustra con un código C. La salida en el libro es:
main thread pid is 14608
child thread pid is 14610
Y en mi Ubuntu 16.04 es:
main thread pid is 3615
child thread pid is 3615
ps
La salida es compatible con esto.
Supongo que algo debe haber cambiado entre 2001 y ahora.
El siguiente subcapítulo en la página siguiente, 4.5.1 Manejo de señales, se basa en la declaración anterior:
El comportamiento de la interacción entre señales y subprocesos varía de un sistema tipo UNIX a otro. En GNU / Linux, el comportamiento está dictado por el hecho de que los hilos se implementan como procesos.
Y parece que esto será aún más importante más adelante en el libro. ¿Alguien podría explicar lo que está pasando aquí?
He visto este. ¿Los hilos del kernel de Linux son realmente procesos del kernel? , pero no ayuda mucho. Estoy confundido.
Este es el código C:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_function (void* arg)
{
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
getpid
devuelve lo que se llamaría una ID de grupo de subprocesos y para obtener una ID única para un proceso que debe usargettid
. Sin embargo, aparte del núcleo, la mayoría de las personas y las herramientas llamarán a un grupo de subprocesos un proceso, y llamarán a un proceso un subproceso, por coherencia con otros sistemas.Respuestas:
Creo que esta parte de la
clone(2)
página del manual puede aclarar la diferencia re. el PID:La frase "los subprocesos se implementan como procesos" se refiere al tema de los subprocesos que tuvieron PID separados en el pasado. Básicamente, Linux originalmente no tenía subprocesos dentro de un proceso, solo procesos separados (con PID separados) que podrían haber tenido algunos recursos compartidos, como memoria virtual o descriptores de archivos.
CLONE_THREAD
y la separación de la ID del proceso (*) y la ID del hilo hacen que el comportamiento de Linux se parezca más a otros sistemas y más a los requisitos POSIX en este sentido. Aunque técnicamente el sistema operativo todavía no tiene implementaciones separadas para subprocesos y procesos.El manejo de la señal era otra área problemática con la implementación anterior, esto se describe con más detalle en el documento al que @FooF se refiere en su respuesta .
Como se señaló en los comentarios, Linux 2.4 también se lanzó en 2001, el mismo año que el libro, por lo que no es sorprendente que las noticias no lleguen a esa impresión.
fuente
Tienes razón, de hecho "algo debe haber cambiado entre 2001 y ahora". El libro que está leyendo describe el mundo según la primera implementación histórica de hilos POSIX en Linux, llamada LinuxThreads (vea también el artículo de Wikipedia para algunos).
LinuxThreads tuvo algunos problemas de compatibilidad con el estándar POSIX, por ejemplo, hilos que no comparten PID, y algunos otros problemas graves. Para solucionar estos defectos, Red Hat encabezó otra implementación llamada NPTL (Biblioteca nativa de hilos POSIX) para agregar el núcleo necesario y la biblioteca de espacio de usuario para alcanzar un mejor cumplimiento POSIX (tomando buenas partes de otro proyecto de reimplementación de IBM llamado NGPT (" Hilos Posix de próxima generación "), consulte el artículo de Wikipedia sobre NPTL ). Las banderas adicionales agregadas a la
clone(2)
llamada al sistema (especialmente loCLONE_THREAD
que@ikkkachu
señala en su respuesta ) es probablemente la parte más evidente de las modificaciones del núcleo. La parte del espacio de usuario del trabajo finalmente se incorporó a la Biblioteca GNU C.Todavía hoy en día, algunos SDK de Linux incorporados usan la antigua implementación de LinuxThreads porque están usando una versión de huella de memoria más pequeña de LibC llamada uClibc (también llamada µClibc) , y pasaron una cantidad considerable de años antes de que la implementación del espacio de usuario NPTL de GNU LibC fuera portada y asumida como implementación predeterminada de subprocesos POSIX, ya que, en general, estas plataformas especiales no se esfuerzan por seguir las últimas modas a la velocidad del rayo. Esto se puede observar al notar que, de hecho, los PID para diferentes subprocesos en esas plataformas también son diferentes a diferencia de lo que especifica el estándar POSIX, al igual que el libro que está leyendo describe. En realidad una vez que llamaste
pthread_create()
, de repente, aumentó el recuento de procesos de uno a tres, ya que se necesitaba un proceso adicional para mantener el desorden.La página del manual de Linux pthreads (7) proporciona una descripción completa e interesante de las diferencias entre los dos. Otra descripción esclarecedora, aunque desactualizada, de las diferencias es este artículo de Ulrich Depper e Ingo Molnar sobre el diseño de NPTL.
Te recomiendo que no te tomes esa parte del libro demasiado en serio. En cambio, recomiendo los hilos POSIX de programación de Butenhof y las páginas de manual POSIX y Linux sobre el tema. Muchos tutoriales sobre el tema son inexactos.
fuente
Los subprocesos (espacio de usuario) no se implementan como procesos como tales en Linux, ya que no tienen su propio espacio de direcciones privadas, aún comparten el espacio de direcciones del proceso principal.
Sin embargo, estos subprocesos se implementan para usar el sistema de contabilidad de procesos del kernel, por lo que se les asigna su propio ID de subproceso (TID), pero se les da el mismo PID y 'ID de grupo de subprocesos' (TGID) que el proceso principal; esto contrasta con una bifurcación, donde se crean un nuevo TGID y PID, y el TID es el mismo que el PID.
Entonces, parece que los núcleos recientes tenían un TID separado que se puede consultar, esto es diferente para los subprocesos, un fragmento de código adecuado para mostrar esto en cada una de las principales () thread_function () anterior es:
Entonces, el código completo con esto es:
Dando un ejemplo de salida de:
fuente
Básicamente, la información en su libro es históricamente precisa, debido a un historial de implementación vergonzosamente malo de hilos en Linux. Esta respuesta de mí a una pregunta relacionada sobre SO también sirve como respuesta a su pregunta:
https://stackoverflow.com/questions/9154671/distinction-between-processes-and-threads-in-linux/9154725#9154725
fuente
Internamente, no existen procesos o subprocesos en el kernel de Linux. Los procesos y los subprocesos son principalmente un concepto de tierra de usuario, el núcleo solo ve "tareas", que son un objeto programable que puede compartir ninguno, algunos o todos sus recursos con otras tareas. Los subprocesos son tareas que se han configurado para compartir la mayoría de sus recursos (espacio de direcciones, mmaps, canalizaciones, controladores de archivos abiertos, sockets, etc.) con la tarea principal, y los procesos son tareas que se han configurado para compartir recursos mínimos con la tarea principal .
Cuando usa la API de Linux directamente ( clone () , en lugar de fork () y pthread_create () ), tiene mucha más flexibilidad para definir cuántos recursos compartir o no compartir, y puede crear tareas que no son totalmente proceso ni completamente un hilo. Si usa estas llamadas de bajo nivel directamente, también es posible crear una tarea con un nuevo TGID (tratado así como un proceso por la mayoría de las herramientas de usuario) que realmente comparte todos sus recursos con la tarea principal, o viceversa, para crear una tarea con TGID compartido (por lo tanto, tratada como un hilo por la mayoría de las herramientas de userland) que no comparte ningún recurso con su tarea principal.
Si bien Linux 2.4 implementa TGID, esto es principalmente para beneficio de la contabilidad de recursos. Muchos usuarios y herramientas de espacio de usuario encuentran útil poder agrupar tareas relacionadas e informar sobre el uso de sus recursos.
La implementación de tareas en Linux es mucho más fluida que la cosmovisión de procesos e hilos presentada por las herramientas de espacio de usuario.
fuente
Linus Torvalds declaró en una publicación de la lista de correo del núcleo en 1996 que "tanto los subprocesos como los procesos se tratan como un 'contexto de ejecución'", que es "solo un conglomerado de todo el estado de ese CoE ... incluye cosas como CPU estado, estado MMU, permisos y varios estados de comunicación (archivos abiertos, manejadores de señales, etc.) ".
Como puede ver, este programa generará 25 hilos a la vez, cada uno de los cuales dormirá durante 100 segundos y luego se unirá al programa principal nuevamente. Después de que los 25 hilos se hayan unido al programa, el programa estará listo y se cerrará.
Utilizando
top
podrás ver 25 instancias del programa "threads2". Pero es un niño aburrido. La salida deps auwx
es aún menos interesante ... PERO seps -eLf
vuelve un poco emocionante.Puede ver aquí los 26 CoE que
thread2
ha creado el programa. Todos comparten la misma ID de proceso (PID) e ID de proceso principal (PPID), pero cada uno tiene una ID de LWP (proceso de peso ligero) diferente, y la cantidad de LWP (NLWP) indica que hay 26 CoE: el programa principal y el 25 hilos generados por él.fuente
Cuando se trata de procesos y subprocesos de Linux, son más o menos lo mismo. Es decir, que se crean con la misma llamada al sistema:
clone
.Si lo piensa, la diferencia entre subprocesos y procesos está en que los objetos del núcleo serán compartidos por el elemento secundario y el elemento primario. Para los procesos, no es mucho: descriptores de archivos abiertos, segmentos de memoria en los que no se ha escrito, probablemente algunos otros que no se me ocurren. Para los hilos, se comparten muchos más objetos, pero no todos.
Lo que acerca los hilos y los objetos en Linux es la
unshare
llamada al sistema. Los objetos del núcleo que comienzan como compartidos se pueden compartir después de la creación de subprocesos. Por lo tanto, puede tener dos subprocesos del mismo proceso que tengan un espacio de descriptor de archivo diferente (al revocar el uso compartido de descriptores de archivo después de crear los subprocesos). Puede probarlo usted mismo creando un hilo, llamandounshare
a ambos hilos y luego cerrando todos los archivos y abriendo nuevos archivos, tuberías u objetos en ambos hilos. Luego mire/proc/your_proc_fd/task/*/fd
y verá que cada unotask
(que creó como un hilo) tendrá diferentes fd.De hecho, tanto la creación de nuevos subprocesos como los nuevos procesos son rutinas de biblioteca que llaman
clone
debajo y especifican cuál de los objetos del núcleotask
compartirá el proceso-thread-thingamajig (es decir, ) recién creado con el proceso / hilo de llamada.fuente