GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo crear subprocesos en Linux (con un programa de ejemplo en C)

En la parte I de la serie Linux Threads, discutimos varios aspectos relacionados con los hilos en Linux.

En este artículo nos centraremos en cómo se crea e identifica un hilo. También presentaremos un ejemplo de programa funcional en C que explicará cómo realizar una programación básica con subprocesos.

Serie de subprocesos de Linux:parte 1, parte 2 (este artículo), parte 3.

Identificación de subprocesos

Así como un proceso se identifica a través de un ID de proceso, un subproceso se identifica mediante un ID de subproceso. Pero curiosamente, la similitud entre los dos termina aquí.

  • Un ID de proceso es único en todo el sistema, mientras que un ID de subproceso es único solo en el contexto de un solo proceso.
  • Un Id. de proceso es un valor entero, pero el Id. de subproceso no es necesariamente un valor entero. Bien podría ser una estructura
  • Un ID de proceso se puede imprimir muy fácilmente mientras que un ID de subproceso no es fácil de imprimir.

Los puntos anteriores dan una idea de la diferencia entre un ID de proceso y un ID de subproceso.

El ID del subproceso está representado por el tipo 'pthread_t'. Como ya comentamos, en la mayoría de los casos este tipo es una estructura, por lo que debe haber una función que pueda comparar dos ID de subprocesos.

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);

Entonces, como puede ver, la función anterior toma dos ID de subprocesos y devuelve un valor distinto de cero si ambos ID de subprocesos son iguales o devuelve cero.

Puede surgir otro caso en el que un subproceso desee conocer su propio ID de subproceso. Para este caso, la siguiente función proporciona el servicio deseado.

#include <pthread.h>
pthread_t pthread_self(void);

Entonces vemos que la función 'pthread_self()' es utilizada por un hilo para imprimir su propia ID de hilo.

Ahora, uno preguntaría sobre el caso en el que se requerirían las dos funciones anteriores. Supongamos que hay un caso en el que una lista de enlaces contiene datos para diferentes subprocesos. Cada nodo de la lista contiene un ID de subproceso y los datos correspondientes. Ahora, cada vez que un subproceso intenta obtener sus datos de la lista vinculada, primero obtiene su propia ID llamando a 'pthread_self()' y luego llama a 'pthread_equal()' en cada nodo para ver si el nodo contiene datos para él o no. .

Un ejemplo del caso genérico discutido anteriormente sería aquel en el que un subproceso maestro obtiene los trabajos que se procesarán y luego los inserta en una lista de enlaces. Ahora, los subprocesos de trabajo individuales analizan la lista vinculada y extraen el trabajo que se les asignó.

Creación de hilos

Normalmente, cuando un programa se inicia y se convierte en un proceso, comienza con un subproceso predeterminado. Entonces podemos decir que cada proceso tiene al menos un hilo de control. Un proceso puede crear subprocesos adicionales utilizando la siguiente función:

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg)

La función anterior requiere cuatro argumentos, primero analicemos un poco sobre ellos:

  • El primer argumento es una dirección de tipo pthread_t. Una vez que la función se llama con éxito, la variable cuya dirección se pasa como primer argumento contendrá la identificación del hilo del hilo recién creado.
  • El segundo argumento puede contener ciertos atributos que queremos que contenga el nuevo hilo. Podría ser prioridad, etc.
  • El tercer argumento es un puntero de función. Esto es algo para tener en cuenta que cada subproceso comienza con una función y que la dirección de funciones se pasa aquí como el tercer argumento para que el núcleo sepa desde qué función iniciar el subproceso.
  • Como la función (cuya dirección se pasa en el tercer argumento anterior) también puede aceptar algunos argumentos para que podamos pasar estos argumentos en forma de un puntero a un tipo vacío. Ahora bien, ¿por qué se eligió un tipo vacío? Esto se debió a que si una función acepta más de un argumento, este puntero podría ser un puntero a una estructura que puede contener estos argumentos.

Un ejemplo práctico de hilo

El siguiente es el código de ejemplo en el que intentamos usar las tres funciones discutidas anteriormente.

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    pthread_t id = pthread_self();

    if(pthread_equal(id,tid[0]))
    {
        printf("\n First thread processing\n");
    }
    else
    {
        printf("\n Second thread processing\n");
    }

    for(i=0; i<(0xFFFFFFFF);i++);

    return NULL;
}

int main(void)
{
    int i = 0;
    int err;

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
            printf("\n Thread created successfully\n");

        i++;
    }

    sleep(5);
    return 0;
}

Entonces, lo que hace este código es:

  • Utiliza la función pthread_create() para crear dos hilos
  • La función de inicio para ambos subprocesos se mantiene igual.
  • Dentro de la función 'doSomeThing()', el subproceso utiliza las funciones pthread_self() y pthread_equal() para identificar si el subproceso en ejecución es el primero o el segundo creado.
  • Además, dentro de la misma función 'doSomeThing()' se ejecuta un bucle for para simular un trabajo que requiere mucho tiempo.

Ahora, cuando se ejecuta el código anterior, el siguiente fue el resultado:

$ ./threads
Thread created successfully
First thread processing
Thread created successfully
Second thread processing

Como se ve en la salida, se crea el primer subproceso y comienza a procesarse, luego se crea el segundo subproceso y luego comienza a procesarse. Bueno, un punto a tener en cuenta aquí es que el orden de ejecución de los hilos no siempre es fijo. Depende del algoritmo de programación del sistema operativo.

Nota:Toda la explicación en este artículo se realiza en hilos de Posix. Como se puede comprender por el tipo, el tipo pthread_t significa subprocesos POSIX. Si una aplicación quiere probar si los subprocesos POSIX son compatibles o no, entonces la aplicación puede usar la macro _POSIX_THREADS para la prueba de tiempo de compilación. Para compilar un código que contenga llamadas a las API posix, utilice la opción de compilación '-pthread'.


Linux
  1. Cómo crear archivos Proc de Linux en el programa C usando LKM

  2. Cómo terminar un subproceso en un programa C (ejemplo de pthread_exit)

  3. Cómo crear un sistema de archivos ZFS con compresión de archivos en Linux

  4. ¿Cómo crear un archivo con un tamaño determinado en Linux?

  5. Cómo crear un ejemplo de canalización de Linux en c

Cómo crear enlaces simbólicos en Linux

Cómo crear un archivo en Linux

Cómo crear unidades USB de arranque múltiple con Ventoy en Linux

Cómo crear un grupo de volúmenes en Linux con LVM

Cómo crear un libro electrónico con Calibre en Linux [Guía completa]

Cron Vs Anacron:Cómo configurar Anacron en Linux (con un ejemplo)