Aprendizaje de Linux: Procesos

Índice

Ejemplo 1 Obtener el identificador de proceso actual

Ejemplo 2 Crear un nuevo proceso hijo

Ejemplo 3 Mostrar los identificadores de proceso del padre y el hijo

Ejemplo 4 Diferenciar entre procesos padre e hijo

Ejemplo 5 Comportamiento distinto en procesos padre e hijo

Ejemplo 6 Comparar identificadores de proceso para distinguir padre e hijo

Ejemplo 7 Efecto de modificar una variable en el hijo sobre el padre

Ejemplo 8 El hijo crea y ejecuta un bucle, imprimiendo un mensaje cada 3 segundos

Ejemplo 9 Padres e hijos entran en bucles sepraados, imprimiendo mensajes cada segundo

Ejemplo 10 Crear un proceso hijo con vfork()

Ejemplo 11 vfork() crea un proceso hijo que termina automáticamente después de ciertas iteraciones

Ejemplo 12

Ejemplo 13 Crear un proceso hijo, operaciones diferentes para padre e hijo. El hijo sale bajo ciertas condiciones

Ejemplo 14 Padre espera a que el hijo termine antes de continuar

Ejemplo 15 wait() espera a que el hijo termine, padre imprime estado de salida

Ejemplo 16 waitpid() reemplaza wait() para verificar el estado del hijo, permite comprobación no bloqueante o espera específica

Ejemplo 17 El hijo termina bajo ciertas condiciones mientras el padre solo imprime un mensaje

Ejemplo 18 execl() ejecuta un nuevo programa. Esta función pertenece a la familia exec que reemplaza la imagen del proceso actual

Ejemplo 19 Utilizar execl() para ejecutar el comando /bin/ls, comúnmente usado para listar contenido de directorios. Si execl() tiene éxito, no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 20 execl() ejecuta /bin/ls con opción -l para mostrar listado detallado. Si execl() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 21 execl() ejecuta el comando del sistema /bin/date para mostrar fecha y hora del sistema. Si execl() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 22 execlp() ejecuta el comando del sistema ps para mostrar estado de procesos del sistema. Si execlp() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 23 execvp() ejecuta el comando del sistema ps para mostrar estado de procesos del sistema. execvp() es similar a execlp(), pero permite pasar parámetros mediante un array. Si execvp() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 24 execv() ejecuta el comando /bin/ps para mostrar estado de procesos del sistema. execv() es similar a execl(), pero usa arrays para pasar comandos y sus argumentos. Si execv() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

Ejemplo 25 Entrada para activar operaciones de archivo en proceso hijo. Este ejemplo modifica un valor específico en el archivo config.txt cuando la entrada es 1

Ejemplo 26 Decidir según entrada si crear un proceso hijo para ejecutar un programa específico (changData), esperando modificar config.txt. Si entrada no es 1, imprime mensaje y sigue esperando

Ejemplo 27 Decidir según entrada ejecutar un comando externo (changData) relacionado con config.txt. Si se introduce 1, se crea un proceso hijo que invoca el programa externo ./changData a través de system() para manipular config.txt

Ejemplo 28 system() ejecuta comandos del sistema (en este caso ps), utilizado para listar procesos en ejecución. Sin embargo, este ejemplo tiene un problema: no captura la salida de system()

Ejemplo 29 popen() y fread() obtienen la salida del comando ps y la leen en un array de caracteres. Muestra cómo ejecutar comandos del sistema y capturar su salida, útil para leer datos directamente de herramientas de línea de comandos

Ejemplo 30 Manejo de argumentos de línea de comandos. Imprime todos los argumentos pasados al programa recorriendo los arrays argc y argv

Ejemplo 31 Espera entrada del usuario. Cuando se introduce 1, se crea un proceso hijo que modifica caracteres después de la cadena "LENG=" en el archivo ./file1

Ejemplo 32 La función execl() sustituye la imagen del proceso actual por el proceso de /bin/ls

Ejemplo 33 vfork() crea un proceso hijo y controla el orden de ejecución

Ejemplo 1 Obtener el identificador de proceso actual

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid()

int main()
{
    pid_t process_id;  // Definir variable para identificador de proceso

    process_id = getpid(); // Llamar a getpid() para obtener PID del proceso actual

    printf("mi pid es %d\n", process_id);  // Imprimir PID del proceso actual

    while(1);  // Hacer que el programa entre en bucle infinito para evitar salida inmediata

    return 0;  // Normalmente no se llega aquí debido al bucle infinito
}

Ejemplo 2 Crear un nuevo proceso hijo

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t process_id;  // Definir variable para identificador de proceso

    process_id = getpid(); // Llamar a getpid() para obtener PID del proceso actual

    fork(); // Llamar a fork() para crear un proceso hijo. En el padre, fork devuelve el PID del hijo; en el hijo, devuelve 0.

    printf("mi pid es %d\n", process_id);  // Imprimir PID actual, se ejecutará tanto en padre como en hijo.

    return 0;  // Finalizar programa, tanto padre como hijo llegarán aquí y terminarán
}

Ejemplo 3 Mostrar los identificadores de proceso del padre y el hijo

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t process_id;  // Definir variable para identificador de proceso

    process_id = getpid(); // Llamar a getpid() para obtener PID del proceso actual

    fork(); // Llamar a fork() para crear un proceso hijo. En el padre, fork devuelve el PID del hijo; en el hijo, devuelve 0.

    // Imprimir PID inicial y PID actual.
    // "process_id" es el PID del proceso padre antes de fork().
    // "getpid()" obtiene el PID del proceso actual, que puede ser diferente en padre e hijo.
    printf("mi pid es %d, id proceso actual:%d\n", process_id, getpid());

    return 0;  // Finalizar programa, tanto padre como hijo llegarán aquí y terminarán
}

Ejemplo 4 Diferenciar entre procesos padre e hijo

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t original_pid;  // Variable para almacenar PID del proceso original
    pid_t new_pid;       // Variable para almacenar PID tras fork()

    original_pid = getpid(); // Obtener y almacenar PID del proceso actual
    printf("antes de fork: pid = %d\n", original_pid); // Imprimir PID antes de fork

    fork(); // Crear nuevo proceso hijo. Padre recibe PID del hijo; hijo recibe 0.

    new_pid = getpid(); // Obtener PID del proceso tras fork
    printf("después de fork: pid = %d\n", new_pid); // Imprimir PID tras fork

    if(original_pid == new_pid)
    {
        // Si PID antes y después son iguales, código en proceso padre
        printf("esto es impresión del padre\n");
    }
    else
    {
        // Si PID antes y después son distintos, código en proceso hijo
        printf("esto es impresión del hijo, pid del hijo = %d\n", getpid());
    }

    return 0;  // Programa termina, ambos procesos llegarán aquí y saldrán
}

Ejemplo 5 Comportamiento distinto en procesos padre e hijo

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t fork_result; // Variable para almacenar resultado de fork()

    // Imprimir PID del proceso actual, que es el padre
    printf("padre: id=%d\n", getpid());

    fork_result = fork(); // Llamar a fork() para crear proceso hijo

    if (fork_result > 0)
    {
        // Si fork_result mayor que 0, es el bloque de código del padre
        // En padre, fork() devuelve PID del proceso hijo creado
        printf("esto es impresión del padre, pid = %d\n", getpid());
    }
    
    else if (fork_result == 0)
    {
        // Si fork_result igual a 0, es el bloque de código del hijo
        // En hijo, fork() devuelve 0
        printf("esto es impresión del hijo, pid del hijo = %d\n", getpid());
    }

    // Ambos procesos llegarán aquí y terminarán
    return 0;
}

Ejemplo 6 Comparar identificadores de proceso para distinguir padre e hijo

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t original_pid;     // Variable para almacenar PID original
    pid_t current_pid;      // Variable para almacenar PID actual
    pid_t fork_return;      // Variable para almacenar resultado de fork()

    original_pid = getpid(); // Obtener y almacenar PID del proceso actual
    printf("antes de fork: pid = %d\n", original_pid); // Imprimir PID antes de fork

    fork_return = fork(); // Crear nuevo proceso hijo. Padre recibe PID del hijo; hijo recibe 0.

    current_pid = getpid(); // Obtener PID del proceso actual tras fork
    printf("después de fork: pid = %d\n", current_pid); // Imprimir PID tras fork

    if(original_pid == current_pid)
    {
        // Si PID antes y después son iguales, código en proceso padre
        // fork_return será PID del hijo, ya que en padre fork() devuelve PID del hijo
        printf("esto es impresión del padre: fork_return = %d\n", fork_return);
    }
    else
    {
        // Si PID antes y después son distintos, código en proceso hijo
        // En hijo, fork() devuelve 0
        printf("esto es impresión del hijo, fork_return=%d, pid del hijo = %d\n", fork_return, getpid());
    }

    return 0;  // Programa termina, ambos procesos llegarán aquí y saldrán
}

Ejemplo 7 Efecto de modificar una variable en el hijo sobre el padre

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid() y fork()

int main()
{
    pid_t fork_result; // Variable para almacenar resultado de fork()
    int data_value = 10; // Definir variable entera data_value e inicializarla en 10

    // Imprimir PID del proceso actual, que es el padre
    printf("padre: id=%d\n", getpid());

    fork_result = fork(); // Llamar a fork() para crear proceso hijo

    if (fork_result > 0)
    {
        // Si fork_result mayor que 0, es el bloque de código del padre
        // En padre, fork() devuelve PID del proceso hijo creado
        printf("esto es impresión del padre, pid = %d\n", getpid());
    }
    
    else if (fork_result == 0)
    {
        // Si fork_result igual a 0, es el bloque de código del hijo
        // En hijo, fork() devuelve 0
        printf("esto es impresión del hijo, pid del hijo = %d\n", getpid());

        // Modificar variable data_value en proceso hijo
        data_value = data_value + 100; // Sumar 100 a data_value
    }

    // Tanto padre como hijo llegarán aquí e imprimirán valor de data_value
    printf("data=%d\n", data_value);

    return 0; // Programa termina, ambos procesos llegarán aquí y saldrán
}

Ejemplo 8 El hijo crea y ejecuta un bucle, imprimiendo un mensaje cada 3 segundos

#include <stdio.h>   // Incluir biblioteca estándar de entrada/salida para impresión y entrada
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int input_data = 10; // Definir variable entera input_data e inicializarla en 10

    while(1) { // Bucle infinito

        printf("por favor ingrese un dato\n"); // Solicitar entrada de datos al usuario
        scanf("%d", &input_data); // Leer entero desde entrada estándar a variable input_data

        if(input_data == 1) { // Si entrada es 1
            
            process_id = fork(); // Llamar a fork() para crear proceso hijo
            
            if(process_id > 0) {
                // Si process_id mayor que 0, es el bloque de código del padre
                // Padre no hace nada, continúa bucle esperando nueva entrada
            }
            else if(process_id == 0) {
                // Si process_id igual a 0, es el bloque de código del hijo
                // En hijo, fork() devuelve 0
                while(1) {
                    // Hijo entra en otro bucle infinito, imprimiendo mensaje cada 3 segundos
                    printf("no hacer solicitud, pid=%d\n", getpid()); // Imprimir PID del hijo actual
                    sleep(3); // Hijo duerme 3 segundos
                }
            }
        }
        else {
            // Si entrada no es 1
            printf("esperando, no hacer nada\n"); // Imprimir mensaje de espera
        }
    }

    return 0; // Programa teóricamente no llega aquí, debido al bucle infinito
}

Ejemplo 9 Padres e hijos entran en bucles separados, imprimiendo mensajes cada segundo

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        // Padre entra en bucle infinito
        while (1) {
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle para evitar consumo excesivo de recursos
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo, mismo propósito que en padre
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 10 vfork() crea un proceso hijo

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), vfork() y sleep()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de vfork()

    process_id = vfork(); // Llamar a vfork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        // Padre entra en bucle infinito
        while (1) {
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo, mismo propósito que en padre
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 11 vfork() crea un proceso hijo que termina automáticamente después de ciertas iteraciones

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), vfork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de vfork()
    int counter = 0; // Definir e inicializar contador

    process_id = vfork(); // Llamar a vfork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        // Padre entra en bucle infinito
        while (1) {
            printf("contador=%d\n", counter); // Imprimir valor del contador en padre
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 3) {
                exit(0); // Cuando contador alcance 3, hijo termina
                break;   // Salir del bucle
            }
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 12

Ejemplo 13 Crear un proceso hijo, operaciones diferentes para padre e hijo. El hijo sale bajo ciertas condiciones

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int counter = 0; // Definir e inicializar contador

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        // Padre entra en bucle infinito
        while (1) {
            printf("contador=%d\n", counter); // Imprimir valor del contador en padre
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 5) {
                exit(0); // Cuando contador alcance 5, hijo termina
            }
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 14 Padre espera a que el hijo termine antes de continuar

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()
#include <sys/wait.h>  // Incluir biblioteca necesaria para función wait()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int counter = 0; // Definir e inicializar contador

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        wait(NULL);  // Padre espera cualquier proceso hijo que termine, no importa estado de salida
        // Padre continúa ejecución tras terminar hijo
        while (1) {
            printf("contador=%d\n", counter); // Imprimir valor del contador en padre
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 5) {
                exit(0); // Cuando contador alcance 5, hijo termina
            }
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 15 wait() espera a que el hijo termine, padre imprime estado de salida

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()
#include <sys/wait.h>  // Incluir biblioteca necesaria para función wait()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int counter = 0; // Definir e inicializar contador
    int exit_status = 10; // Definir entero para almacenar estado de salida del hijo

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        wait(&exit_status); // Padre espera hijo que termine y obtiene estado de salida mediante exit_status
        printf("hijo terminado, estado del hijo = %d\n", WEXITSTATUS(exit_status)); // Imprimir estado de salida del hijo

        // Padre continúa ejecución tras terminar hijo
        while (1) {
            printf("contador=%d\n", counter); // Imprimir valor del contador en padre
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 5) {
                exit(3); // Cuando contador alcance 5, hijo termina y devuelve estado 3
            }
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 16 waitpid() reemplaza wait() para verificar estado del hijo, waitpid() permite verificación no bloqueante o espera específica

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), fork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()
#include <sys/wait.h>  // Incluir biblioteca necesaria para función waitpid()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int counter = 0; // Definir e inicializar contador
    int exit_status = 10; // Definir entero para almacenar estado de salida del hijo

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        waitpid(process_id, &exit_status, WNOHANG); // Usar modo no bloqueante para esperar hijo, padre no se queda bloqueado
        printf("hijo terminado, estado del hijo = %d\n", WEXITSTATUS(exit_status)); // Imprimir estado de salida del hijo

        // Padre continúa ejecución tras terminar hijo
        while (1) {
            printf("contador=%d\n", counter); // Imprimir valor del contador en padre
            printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
            sleep(1); // Padre duerme 1 segundo, ralentiza velocidad del bucle
        }    
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito
        while (1) {
            printf("esto es impresión del hijo, pid = %d\n", getpid()); // Imprimir información y PID del hijo
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 5) {
                exit(3); // Cuando contador alcance 5, hijo termina y devuelve estado 3
            }
        }    
    }

    return 0; // Programa teóricamente no llega aquí, ambos procesos están en bucles infinitos
}

Ejemplo 17 El hijo termina bajo ciertas condiciones mientras el padre solo imprime un mensaje

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <sys/types.h> // Incluir tipos de datos, incluyendo pid_t
#include <unistd.h>    // Incluir API POSIX, incluyendo getpid(), getppid(), fork() y sleep()
#include <stdlib.h>    // Incluir biblioteca estándar, para exit()

int main()
{
    pid_t process_id; // Variable para almacenar resultado de fork()
    int counter = 0; // Definir e inicializar contador

    process_id = fork(); // Llamar a fork() para crear proceso hijo
    
    if (process_id > 0)
    {
        // Si process_id mayor que 0, es el bloque de código del padre
        printf("esto es impresión del padre, pid = %d\n", getpid()); // Imprimir información y PID del padre
        // Padre no entra en bucle, termina ejecución directamente
    }
    
    else if (process_id == 0) {
        // Si process_id igual a 0, es el bloque de código del hijo
        // Hijo entra en bucle infinito hasta que counter sea 5
        while (1) {
            printf("esto es impresión del hijo, pid = %d, pid del padre=%d\n", getpid(), getppid()); // Imprimir información del hijo y PID del padre
            sleep(1); // Hijo duerme 1 segundo
            counter++; // Aumentar contador en hijo
            if (counter == 5) {
                exit(3); // Cuando contador alcance 5, hijo termina y devuelve estado 3
            }
        }    
    }

    return 0; // Padre imprime y termina, hijo termina cuando counter alcanza 5
}

Ejemplo 18 execl() ejecuta un nuevo programa. Esta función pertenece a la familia exec que reemplaza la imagen del proceso actual

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execl()

// Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    // Imprimir "antes de execl" indicando que estamos antes de llamar a execl
    printf("antes de execl\n");

    // Llamar a execl para ejecutar programa llamado "echoarg", debe estar en directorio actual
    // "echoarg" es nombre del programa ejecutado, también primer parámetro pasado al programa
    // "abc" es segundo parámetro pasado al programa echoarg
    // NULL indica fin de lista de parámetros
    if(execl("./echoarg", "echoarg", "abc", NULL) == -1)
    {
        // Si execl devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execl no retorna en caso de éxito, si llegamos aquí significa fallo en execl
    printf("después de execl\n");

    return 0;
}

Ejemplo 19 execl() ejecuta el comando /bin/ls, comúnmente usado para listar contenido de directorios. Si execl() tiene éxito, no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execl()

// Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    // Imprimir "antes de execl" indicando que estamos antes de llamar a execl
    printf("antes de execl\n");

    // Llamar a execl para ejecutar programa en "/bin/ls", comúnmente usado para listar directorios
    // "ls" es parámetro pasado al programa /bin/ls para identificar el nombre del programa
    // NULL indica fin de lista de parámetros
    if(execl("/bin/ls", "ls", NULL, NULL) == -1)
    {
        // Si execl devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");      

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execl no retorna en caso de éxito, si llegamos aquí significa fallo en execl
    printf("después de execl\n");

    return 0;
}

Ejemplo 20 execl() ejecuta /bin/ls con opción -l para mostrar listado detallado. Si execl() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execl()

// Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    // Imprimir "antes de execl" indicando que estamos antes de llamar a execl
    printf("antes de execl\n");

    // Llamar a execl para ejecutar programa en "/bin/ls" usando opción "-l" para mostrar listado detallado
    // "ls" es parámetro pasado al programa /bin/ls para identificar el nombre del programa
    // "-l" es parámetro que indica a ls usar formato largo para mostrar información
    // NULL indica fin de lista de parámetros
    if(execl("/bin/ls", "ls", "-l", NULL) == -1)
    {
        // Si execl devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");      

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execl no retorna en caso de éxito, si llegamos aquí significa fallo en execl
    printf("después de execl\n");

    return 0;
}

Ejemplo 21 execl() ejecuta comando del sistema /bin/date, usado para mostrar fecha y hora del sistema. Si execl() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execl()

// Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    // Imprimir información indicando que el programa obtendrá fecha del sistema
    printf("este programa obtiene fecha del sistema:\n");

    // Llamar a execl para ejecutar comando del sistema "/bin/date"
    // "date" es parámetro pasado al programa /bin/date para identificar el nombre del programa
    // NULL indica fin de lista de parámetros
    if(execl("/bin/date", "date", NULL, NULL) == -1)
    {
        // Si execl devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");      

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execl no retorna en caso de éxito, si llegamos aquí significa fallo en execl
    printf("después de execl\n");

    return 0;
}

Ejemplo 22 execlp() ejecuta comando del sistema ps, usado para mostrar estado de procesos del sistema. Si execlp() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execlp()

// Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    // Imprimir información indicando que el programa obtendrá estado de procesos del sistema
    printf("este programa obtiene estado de procesos del sistema:\n");

    // Llamar a execlp para ejecutar comando del sistema "ps"
    // "ps" es parámetro pasado a execlp() para ejecutar comando ps que muestra información de procesos
    // NULL indica fin de lista de parámetros
    if(execlp("ps", "ps", NULL, NULL) == -1)
    {
        // Si execlp devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execlp no retorna en caso de éxito, si llegamos aquí significa fallo en execlp
    printf("después de execl\n");

    return 0;
}

Ejemplo 23 execvp() ejecuta comando del sistema ps para mostrar estado de procesos del sistema. execvp() es similar a execlp(), pero permite pasar parámetros mediante un array. Si execvp() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execvp()

// Prototipo de función: int execvp(const char *file, char *const argv[]);

int main(void)
{
    // Imprimir información indicando que el programa obtendrá estado de procesos del sistema
    printf("este programa obtiene estado de procesos del sistema:\n");

    // Crear array de parámetros para pasar a execvp()
    char *args[] = {"ps", NULL, NULL};

    // Llamar a execvp para ejecutar comando del sistema "ps"
    // "ps" es el comando a ejecutar, args es el array de comandos y parámetros
    if(execvp("ps", args) == -1)
    {
        // Si execvp devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");      

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execvp no retorna en caso de éxito, si llegamos aquí significa fallo en execvp
    printf("después de execl\n");

    return 0;
}

Ejemplo 24 execv() ejecuta comando /bin/ps, usado para mostrar estado de procesos del sistema. execv() es similar a execl(), pero usa arrays para pasar comandos y sus parámetros. Si execv() tiene éxito, reemplaza la imagen del proceso actual y no retorna; si falla, retorna -1 e imprime mensaje de error

#include <stdio.h>    // Incluir biblioteca estándar de entrada/salida para impresión
#include <stdlib.h>   // Incluir biblioteca estándar para funcionalidades estándar
#include <unistd.h>   // Incluir API POSIX, incluyendo execv()

// Prototipo de función: int execv(const char *path, char *const argv[]);

int main(void)
{
    // Imprimir información indicando que el programa obtendrá estado de procesos del sistema
    printf("este programa obtiene estado de procesos del sistema:\n");

    // Crear array de parámetros para pasar a execv()
    char *args[] = {"ps", NULL, NULL};  // "ps" es nombre del comando, NULL indica fin de lista de parámetros

    // Llamar a execv para ejecutar comando en "/bin/ps"
    // "/bin/ps" es ruta completa del comando
    // args es el array de comandos y parámetros
    if(execv("/bin/ps", args) == -1)
    {
        // Si execv devuelve -1, significa fallo en ejecución
        printf("execl falló!\n");

        // perror imprime descripción del último error (basado en variable global errno)
        perror("por qué");
    }

    // Como execv no retorna en caso de éxito, si llegamos aquí significa fallo en execv
    printf("después de execl\n");

    return 0;
}

Ejemplo 25 Entrada para activar operaciones de archivo en proceso hijo. Este ejemplo modifica un valor específico en el archivo config.txt cuando la entrada es 1

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

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    pid_t process_id;  // Para almacenar ID de proceso
    int input_data = 10;  // Datos de entrada del usuario inicializados en 10

    while(1) {  // Bucle infinito hasta que el programa sea terminado externamente

        printf("por favor ingrese un dato\n");  // Solicitar entrada de datos al usuario
        scanf("%d", &input_data);  // Leer entero desde entrada estándar a variable input_data

        if(input_data == 1) {  // Si entrada es 1, realizar operación de archivo
            int file_descriptor;  // Descriptor de archivo

            process_id = fork();  // Crear proceso hijo
            if(process_id > 0) {
                wait(NULL);  // Padre espera que hijo termine
            }

            if(process_id == 0) {  // Bloque de código del proceso hijo
                char *buffer_read = NULL;  // Puntero para buffer de lectura

                file_descriptor = open("config.txt", O_RDWR);  // Abrir archivo config.txt para lectura/escritura
                int file_size = lseek(file_descriptor, 0, SEEK_END);  // Obtener tamaño del archivo
                lseek(file_descriptor, 0, SEEK_SET);  // Reiniciar puntero al inicio del archivo

                buffer_read = (char *)malloc(sizeof(char) * file_size + 8);  // Asignar memoria para buffer de lectura

                int bytes_read = read(file_descriptor, buffer_read, file_size);  // Leer contenido del archivo al buffer

                char *found_position = strstr(buffer_read, "LENG=");  // Buscar "LENG=" en el buffer
                if(found_position == NULL) {
                    printf("no encontrado\n");  // Si no se encuentra, imprimir mensaje y salir
                    exit(-1);
                }

                found_position = found_position + strlen("LENG=");  // Mover puntero después de "LENG="
                *found_position = '5';  // Modificar contenido

                lseek(file_descriptor, 0, SEEK_SET);  // Reiniciar puntero al inicio del archivo
                int bytes_written = write(file_descriptor, buffer_read, strlen(buffer_read));  // Escribir contenido modificado al archivo
                
                close(file_descriptor);  // Cerrar archivo
                exit(0);  // El hijo termina
            }

        } else {
            printf("esperando, no hacer nada\n");  // Si entrada no es 1, imprimir mensaje de espera
        }
    }

    return 0;  // Bucle principal del programa, en realidad nunca se llega aquí
}

Ejemplo 26 Decidir según entrada si crear un proceso hijo para ejecutar un programa específico (changData), esperando modificar config.txt. Si entrada no es 1, imprime mensaje y sigue esperando

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

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    pid_t process_id;  // Para almacenar ID de proceso
    int input_data = 10;  // Datos de entrada del usuario inicializados en 10

    while(1) {  // Bucle infinito hasta que el programa sea terminado externamente

        printf("por favor ingrese un dato\n");  // Solicitar entrada de datos al usuario
        scanf("%d", &input_data);  // Leer entero desde entrada estándar a variable input_data

        if(input_data == 1) {  // Si entrada es 1, realizar operación
            int unused_fd;  // Descriptor de archivo, aunque no se use en esta versión del código
            
            process_id = fork();  // Crear proceso hijo
            if(process_id > 0) {
                wait(NULL);  // Padre espera que hijo termine
            }
                    
            if(process_id == 0) {  // Bloque de código del proceso hijo
                // El hijo ejecuta programa externo "changData"
                // Primer parámetro "./changData" especifica ruta del programa
                // Segundo parámetro "changData" es argv[0], nombre del programa
                // Tercer parámetro "config.txt" es parámetro pasado al programa changData, especificando archivo a operar
                // NULL indica fin de lista de parámetros
                execl("./changData", "changData", "config.txt", NULL);

                // Si execl falla, continuará ejecutando el siguiente código
                perror("Error al ejecutar changData");  // Imprimir razón del fallo
                exit(1);  // El hijo termina con error
            }

        } else {
            printf("esperando, no hacer nada\n");  // Si entrada no es 1, imprimir mensaje de espera y no hacer nada
        }
    }

    return 0;  // Bucle principal del programa, en realidad nunca se llega aquí
}

Ejemplo 27 Decidir según entrada ejecutar un comando externo (changData) relacionado con config.txt. Si se introduce 1, se crea un proceso hijo que invoca el programa externo ./changData a través de system() para manipular config.txt

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

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>


int main()
{
    pid_t process_id;  // Para almacenar ID de proceso
    int input_data = 10;  // Datos de entrada del usuario inicializados en 10

    while(1) {  // Bucle infinito hasta que el programa sea terminado externamente

        printf("por favor ingrese un dato\n");  // Solicitar entrada de datos al usuario
        scanf("%d", &input_data);  // Leer entero desde entrada estándar a variable input_data

        if(input_data == 1) {  // Si entrada es 1, realizar operación
            int unused_fd;  // Descriptor de archivo, aunque no se use en esta versión del código
            
            process_id = fork();  // Crear proceso hijo
            if(process_id > 0) {
                wait(NULL);  // Padre espera que hijo termine
            }
                    
            if(process_id == 0) {  // Bloque de código del proceso hijo
                // El hijo ejecuta programa externo "changData" mediante función system()
                // "./changData config.txt" es el comando a ejecutar, pasando 'config.txt' como parámetro
                system("./changData config.txt");

                exit(0);  // Tras ejecutar comando externo, el hijo debe salir normalmente
            }

        } else {
            printf("esperando, no hacer nada\n");  // Si entrada no es 1, imprimir mensaje de espera y no hacer nada
        }
    }

    return 0;  // Bucle principal del programa, en realidad nunca se llega aquí
}

Ejemplo 28 system() ejecuta comandos del sistema (en este caso ps), usado para listar procesos en ejecución. Sin embargo, este ejemplo tiene un problema: no captura la salida de system()

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//Prototipo de función: int execl(const char *path, const char *arg, ...);

int main(void)
{
    char output_buffer[1024] = {0};  // Definir array de caracteres e inicializar todos elementos en 0, para almacenar salida

    system("ps");  // Llamar a función system para ejecutar comando ps, usado para mostrar procesos en ejecución
    // Nota: la función system en realidad no almacena la salida del comando en el array output_buffer
    printf("output_buffer=%s\n", output_buffer);  // Imprimir contenido del array output_buffer, debería ser cadena vacía ya que system no modifica output_buffer
    
    return 0;
}

Ejemplo 29 popen() y fread() obtieenn la salida del comando ps y la leen en un array de caracteres. Muestra cómo ejecutar comandos del sistema y capturar su salida, útil para leer datos directamente de herramientas de línea de comandos

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Prototipo de función: int execl(const char *path, const char *arg, ...);
// size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

int main(void)
{
    char output_buffer[1024] = {0};  // Crear array de caracteres para almacenar salida del comando
    FILE *stream_pointer;  // Puntero a archivo, usado para flujo retornado por popen()

    // Ejecutar comando 'ps' y abrir canal de lectura
    stream_pointer = popen("ps", "r");
    if (stream_pointer == NULL) {  // Verificar si popen abrió correctamente el canal
        perror("Error al ejecutar comando");  // Imprimir detalles del error de popen
        exit(1);  // Salir del programa
    }

    // Leer datos del flujo de salida del comando 'ps' al array output_buffer
    int bytes_read = fread(output_buffer, 1, 1024, stream_pointer);  // Leer máximo 1024 bytes al output_buffer

    // Imprimir número de bytes leídos y contenido
    printf("leídos %d bytes, output_buffer=%s\n", bytes_read, output_buffer);

    // Cerrar canal
    pclose(stream_pointer);

    return 0;
}

Ejemplo 30 Manejo de argumentos de línea de comandos. Imprime todos los argumentos pasados al programa recorriendo los arrays argc y argv

#include <stdio.h>

int main(int argument_count, char *argument_vector[])  // Función main acepta argumentos de línea de comandos: argument_count representa cantidad de argumentos, argument_vector es array de cadenas de argumentos
{
    int index = 0;  // Definir variable para contador de ciclo

    for(index = 0; index < argument_count; index++)  // Recorrer todos los argumentos de línea de comandos
    {
        printf("argument_vector[%d]: %s\n", index, argument_vector[index]);  // Imprimir índice y contenido de cada argumento
    }

    return 0;  // Finalizar programa normalmente
}

Ejemplo 31 Espera entrada del usuario. Cuando se introduce 1, se crea un proceso hijo que modifica caracteres después de la cadena "LENG=" en el archivo ./file1

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    pid_t process_id;  // Para almacenar ID de proceso
    int input_data = 10;  // Datos de entrada del usuario inicializados en 10

    while(1) {  // Bucle infinito hasta que el programa sea terminado externamente

        printf("por favor ingrese un dato\n");  // Solicitar entrada de datos al usuario
        scanf("%d", &input_data);  // Leer entero desde entrada estándar a variable input_data

        if(input_data == 1) {  // Si entrada es 1, realizar operación
            
            process_id = fork();  // Crear proceso hijo
            
            if(process_id > 0) {
                // Bloque de código del proceso padre
                // Padre no hace nada, continúa bucle esperando nueva entrada
            }
            else if(process_id == 0) {
                // Bloque de código del proceso hijo
                char *buffer_read = NULL;  // Puntero para buffer de lectura
                int file_descriptor;  // Descriptor de archivo

                file_descriptor = open("./file1", O_RDWR);  // Abrir archivo file1 para lectura/escritura
                int file_size = lseek(file_descriptor, 0, SEEK_END);  // Obtener tamaño del archivo
                lseek(file_descriptor, 0, SEEK_SET);  // Reiniciar puntero al inicio del archivo

                buffer_read = (char *)malloc(sizeof(char) * file_size + 8);  // Asignar memoria para buffer de lectura

                int bytes_read = read(file_descriptor, buffer_read, file_size);  // Leer contenido del archivo al buffer

                char *found_position = strstr(buffer_read, "LENG=");  // Buscar "LENG=" en el buffer
                if(found_position == NULL) {
                    printf("no encontrado\n");  // Si no se encuentra, imprimir mensaje y salir
                    exit(-1);
                }

                found_position += strlen("LENG=");  // Mover puntero después de "LENG="
                *found_position = '5';  // Modificar contenido

                lseek(file_descriptor, 0, SEEK_SET);  // Reiniciar puntero al inicio del archivo
                int bytes_written = write(file_descriptor, buffer_read, strlen(buffer_read));  // Escribir contenido modificado al archivo
                
                close(file_descriptor);  // Cerrar archivo
                free(buffer_read); // Liberar memoria asignada
                exit(0);  // El hijo termina
            }
        }
        else {
            printf("esperando, no hacer nada\n");  // Si entrada no es 1, imprimir mensaje de espera y no hacer nada
        }
    }

    return 0;  // Bucle principal del programa, en realidad nunca se llega aquí
}

Ejemplo 32 La función execl() sustituye la imagen del proceso actual por el proceso de /bin/ls

#include <stdio.h>   // Incluir archivo de cabecera estándar de entrada/salida.
#include <stdlib.h>  // Incluir archivo de cabecera de biblioteca estándar, para funciones como exit().
#include <unistd.h>  // Incluir definiciones de funciones UNIX, proporciona acceso a APIs POSIX.

// Declaración del prototipo de función: int execl(const char *path, const char *arg, ...);
// La función execl() se usa para ejecutar un archivo especificado, reemplazando la imagen del proceso actual.

int main(void)
{
    printf("antes de execl\n");  // Imprimir información antes de llamar a execl().

    // Llamar a execl() para intentar ejecutar comando /bin/ls para listar contenido de directorios. "ls" es nombre del comando, "-l" es parámetro.
    if(execl("/bin/ls", "ls", "-l", NULL) == -1)
    {
        printf("execl falló!\n");  // Si execl() devuelve -1, significa que la ejecución falló.

        perror("por qué");  // Usar función perror() para mostrar la causa del error. perror() muestra descripción basada en código de error global errno.
    }

    // Si la llamada a execl() tiene éxito, no se ejecutará el siguiente código, porque execl() reemplaza la imagen del proceso actual, no retorna.
    printf("después de execl\n");  // Si execl() falla, se continuará ejecutando este código.
    return 0;  // Finalizar programa normalmente.
}


Ejemplo 33 vfork() crea un proceso hijo y controla el orden de ejecución

#include <stdio.h>   // Incluir archivo de cabecera estándar de entrada/salida, para función printf.
#include <sys/types.h>  // Incluir definiciones de tipos de datos, como pid_t.
#include <unistd.h>  // Incluir APIs POSIX, como vfork y getpid.
#include <stdlib.h>  // Incluir archivo de cabecera de biblioteca estándar, para funciones como exit().

int main()
{
    pid_t process_id;  // Declarar variable tipo pid_t para almacenar ID de proceso.

    int counter = 0;  // Contador, usado para contar iteraciones en proceso hijo.
    
    process_id = vfork();  // Crear proceso hijo, proceso hijo comparte espacio de memoria con proceso padre.
    
    if (process_id > 0)  // Si process_id mayor que 0, indica que el bloque de código se ejecuta en proceso padre.
    {
        while (1) {  // Bucle infinito en proceso padre.
            printf("contador=%d\n", counter);  // Imprimir valor del contador actual (nota: este valor no cambiará en proceso padre).
            printf("esto es impresión del padre, pid = %d\n", getpid());  // Imprimir ID del proceso padre.
            sleep(1);  // Pausar proceso padre durante 1 segundo, para observar la salida.
        }   
    }
    
    else if (process_id == 0) {  // Si process_id igual a 0, indica que el bloque de código se ejecuta en proceso hijo.
        while (1) {  // Bucle infinito en proceso hijo.
            printf("esto es impresión del hijo, pid = %d\n", getpid());  // Imprimir ID del proceso hijo.
            sleep(1);  // Pausar proceso hijo durante 1 segundo, para observar la salida.
            counter++;  // Incrementar contador en proceso hijo.
            if (counter == 3) {  // Cuando contador alcance 3, proceso hijo termina.
                exit(0);  // Llamar a función exit para terminar proceso hijo normalmente.
            }
        }   
    }

    return 0;  // Finalizar programa principal (normalmente este bloque no se ejecuta, debido a bucles infinitos en ambos procesos).
}


Etiquetas: linux procesos fork vfork exec

Publicado el 9-27 15:04