es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Proceso de control de bifurcación mediante biblioteca compartida

Estoy trabajando en un proyecto experimental (solo por diversión) y necesito una forma de controlar el “ritmo” con el que mis procesos se bifurcan. Básicamente, tengo un programa que se bifurca sin estar conectado a sus hijos. El proceso hijo lidera el mismo programa a través de execl.

// otros include

#include "hook.h"

int main()
{
  const char* nombreProg = "main";
  unsigned int hijo<em>i;
  pid</em>t pid;

  for (hijo<em>i = 0; hijo</em>i < 3; hijo<em>i++)
    {
      // Hace cosas irrelevantes aquí
      hook<em>take();
      pid = fork();
      if (pid == 0)
        {
          execl(nombreProg, nombreProg, NULL);
        }
      else
        {
          hook_free();
        }
    }

  return 0;
}

La idea aquí es crear un árbol de procesos de la siguiente manera:

main
  |-p0
  |  |-p00
  |  |  |-p001
  |  |  |-p002
  |  |  |-p003
  |  |-p01
  |  |  |-p011
  |  |  |-p012
  |  |  |-p013
  |  |-p02
  |  |  |-p021
  |  |  |-p022
  |  |  |-p023
  |-p1
  |  |-p10
  |  |  |-p101
  |  |  |-p102
  |  |  |-p103
  |  |-p11
...

Sin embargo, esto termina creando demasiados procesos y el sistema se vuelve inestable. Es por eso que opté por usar una biblioteca compartida (hook.h) para bloquear los procesos cuando se alcanza un número máximo de procesos. Esa es la función de hook_take() y hook_free(), que se definen en un archivo separado hook.h.

#ifndef HOOK_H
#define HOOK_H

#ifdef __cplusplus
extern "C"
{
#endif

#define MAX_HOOKS 1000
extern unsigned int _hooks_count;

void hook_take();
void hook_free();

#ifdef __cplusplus
}
#endif

#endif /* HOOK_H */

Y se implementa en hook.c.

#include "hook.h"
#include <unistd.h>

unsigned int _hooks_count = 0;

void
hook_take()
{
  while (_hooks_count == MAX_HOOKS)
    {
      sleep(1);
    }
  _hooks_count++;
}

void
hook_free()
{
  if (_hooks_count > 0)
    {
      _hooks_count--;
    }
}

hook.c se compila como una biblioteca compartida y se enlaza dinámicamente al programa principal.

Después de investigar un poco, me di cuenta rápidamente de que esto no va a funcionar. Ya que cada proceso creará su propia copia de la variable _hooks_count.

¿Cuál sería la forma más fácil de resolver este problema, sin pasar por muchos problemas? Ten en cuenta que este es solo un proyecto experimental y mi código no necesita ser de calidad empresarial ni nada por el estilo.</unistd.h>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una solución simple a este problema sería utilizar un segmento de memoria compartida para almacenar la variable _hooks_count. De esta manera, todos los procesos pueden acceder y actualizar la misma variable.

    Para implementar esta solución, puedes utilizar las funciones shmget, shmat y shmdt proporcionadas por Linux para crear y adjuntar al segmento de memoria compartida. La función shmget crea un nuevo segmento de memoria compartida o se adjunta a uno existente, mientras que shmat adjunta al proceso que llama al segmento de memoria compartida. La función shmdt separa al proceso que llama del segmento de memoria compartida.

    Así es como puedes modificar tu código para utilizar la memoria compartida:

    #include "hook.h"
    #include <sys shm.h=""> // para funciones de memoria compartida
    
    int main()
    {
      const char* progname = "main";
      unsigned int child_i;
      pid_t pid;
    
      // Crear un segmento de memoria compartida para _hooks_count
      int shmid = shmget(IPC_PRIVATE, sizeof(unsigned int), IPC_CREAT | 0666);
      if (shmid < 0) {
        perror("shmget");
        exit(1);
      }
      unsigned int *hooks_count = (unsigned int*) shmat(shmid, NULL, 0);
      if (hooks_count == (void *) -1) {
        perror("shmat");
        exit(1);
      }
    
      // Inicializar la variable compartida a 0
      *hooks_count = 0;
    
      for (child_i = 0; child_i < 3; child_i++)
        {
          // Realizar algunas cosas irrelevantes aquí
          hook_take(hooks_count);
          pid = fork();
          if (pid == 0)
            {
              // Adjuntar el proceso hijo al mismo segmento de memoria compartida
              unsigned int *child_hooks_count = (unsigned int*) shmat(shmid, NULL, 0);
              if (child_hooks_count == (void *) -1) {
                perror("shmat");
                exit(1);
              }
              // Llamar a execl con el child_hooks_count adjunto
              execl(progname, progname, NULL, child_hooks_count);
            }
          else
            {
              hook_free(hooks_count);
            }
    
        }
    
      // Separarse del segmento de memoria compartida
      shmdt(hooks_count);
      // Marcar el segmento de memoria compartida para su destrucción
      shmctl(shmid, IPC_RMID, NULL);
    
      return 0;
    }
    

    También debes modificar las funciones hook_take y hook_free para que tomen un puntero a la variable compartida _hooks_count:

    #include "hook.h"
    #include <unistd.h>
    
    void
    hook_take(unsigned int *hooks_count)
    {
      while (*hooks_count == MAX_HOOKS)
        {
          sleep(1);
        }
      (*hooks_count)++;
    }
    
    void
    hook_free(unsigned int *hooks_count)
    {
      if (*hooks_count > 0)
        {
          (*hooks_count)--;
        }
    }
    

    Con estas modificaciones, todos los procesos compartirán la misma variable _hooks_count a través del segmento de memoria compartida.</unistd.h>

Comments are closed.