Buscar..


Introducción

Los mecanismos de comunicación entre procesos (IPC) permiten que diferentes procesos independientes se comuniquen entre sí. El estándar C no proporciona ningún mecanismo de IPC. Por lo tanto, todos estos mecanismos están definidos por el sistema operativo del host. POSIX define un extenso conjunto de mecanismos de IPC; Windows define otro conjunto; Y otros sistemas definen sus propias variantes.

Semáforos

Los semáforos se utilizan para sincronizar operaciones entre dos o más procesos. POSIX define dos conjuntos diferentes de funciones de semáforo:

  1. 'System V IPC' - semctl() , semop() , semget() .
  2. 'POSIX Semaphores' - sem_close() , sem_destroy() , sem_getvalue() , sem_init() , sem_open() , sem_post() , sem_trywait() , sem_unlink() .

Esta sección describe los semáforos de IPC del Sistema V, llamados así porque se originaron con el Sistema V de Unix.

Primero, deberás incluir los encabezados requeridos. Las versiones anteriores de POSIX requerían #include <sys/types.h> ; POSIX moderno y la mayoría de los sistemas no lo requieren.

#include <sys/sem.h>

Luego, deberá definir una clave tanto para el padre como para el niño.

#define KEY 0x1111 

Esta clave debe ser la misma en ambos programas o no se referirán a la misma estructura de IPC. Hay formas de generar una clave acordada sin tener que codificar su valor.

A continuación, dependiendo de su compilador, puede o no necesitar hacer este paso: declarar una unión con el fin de realizar operaciones de semáforo.

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short  *array;
};

A continuación, defina sus semwait try ( semwait ) y raise ( semsignal ). Los nombres P y V proceden del holandés.

struct sembuf p = { 0, -1, SEM_UNDO}; # semwait
struct sembuf v = { 0, +1, SEM_UNDO}; # semsignal

Ahora, comience por obtener el ID para su semáforo de IPC.

int id;
// 2nd argument is number of semaphores
// 3rd argument is the mode (IPC_CREAT creates the semaphore set if needed)
if ((id = semget(KEY, 1, 0666 | IPC_CREAT) < 0) {
    /* error handling code */
}

En el padre, inicialice el semáforo para tener un contador de 1.

union semun u;
u.val = 1;
if (semctl(id, 0, SETVAL, u) < 0) { // SETVAL is a macro to specify that you're setting the value of the semaphore to that specified by the union u
    /* error handling code */
}

Ahora, puedes disminuir o incrementar el semáforo según lo necesites. Al comienzo de su sección crítica, disminuye el contador utilizando la función semop() :

if (semop(id, &p, 1) < 0) {
    /* error handling code */
}

Para incrementar el semáforo, usa &v lugar de &p :

if (semop(id, &v, 1) < 0) {
    /* error handling code */
}

Tenga en cuenta que cada función devuelve 0 en caso de éxito y -1 en caso de fallo. No verificar estos estados de retorno puede causar problemas devastadores.


Ejemplo 1.1: Carreras con hilos

El programa a continuación tendrá un proceso de fork un niño y tanto el padre como el niño intentarán imprimir caracteres en el terminal sin ninguna sincronización.

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

int main()
{
    int pid;
    pid =  fork();
    srand(pid);
    if(pid < 0)
    {
        perror("fork"); exit(1);
    }
    else if(pid)
    {
        char *s = "abcdefgh";
        int l = strlen(s);
        for(int i = 0; i < l; ++i)
        {
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
        }
    }
    else
    {
        char *s = "ABCDEFGH";
        int l = strlen(s);
        for(int i = 0; i < l; ++i)
        {
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
        }
    }
}

Salida (1ª carrera):

aAABaBCbCbDDcEEcddeFFGGHHeffgghh

(2da carrera):

aabbccAABddBCeeCffgDDghEEhFFGGHH

La compilación y ejecución de este programa debe darle una salida diferente cada vez.

Ejemplo 1.2: Evita competir con semáforos

Modificando el Ejemplo 1.1 para usar semáforos, tenemos:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define KEY 0x1111

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short  *array;
};

struct sembuf p = { 0, -1, SEM_UNDO};
struct sembuf v = { 0, +1, SEM_UNDO};

int main()
{
    int id = semget(KEY, 1, 0666 | IPC_CREAT);
    if(id < 0)
    {
        perror("semget"); exit(11);
    }
    union semun u;
    u.val = 1;
    if(semctl(id, 0, SETVAL, u) < 0)
    {
        perror("semctl"); exit(12);
    }
    int pid;
    pid =  fork();
    srand(pid);
    if(pid < 0)
    {
        perror("fork"); exit(1);
    }
    else if(pid)
    {
        char *s = "abcdefgh";
        int l = strlen(s);
        for(int i = 0; i < l; ++i)
        {
            if(semop(id, &p, 1) < 0)
            {
                perror("semop p"); exit(13);
            }
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
            putchar(s[i]);
            fflush(stdout);
            if(semop(id, &v, 1) < 0)
            {
                perror("semop p"); exit(14);
            }

            sleep(rand() % 2);
        }
    }
    else
    {
        char *s = "ABCDEFGH";
        int l = strlen(s);
        for(int i = 0; i < l; ++i)
        {
            if(semop(id, &p, 1) < 0)
            {
                perror("semop p"); exit(15);
            }
            putchar(s[i]);
            fflush(stdout);
            sleep(rand() % 2);
            putchar(s[i]);
            fflush(stdout);
            if(semop(id, &v, 1) < 0)
            {
                perror("semop p"); exit(16);
            }

            sleep(rand() % 2);
        }
    }
}

Salida:

aabbAABBCCccddeeDDffEEFFGGHHgghh

Compilar y ejecutar este programa te dará la misma salida cada vez.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow