Ricerca…


introduzione

I meccanismi di comunicazione tra processi (IPC) consentono a diversi processi indipendenti di comunicare tra loro. Lo standard C non fornisce alcun meccanismo IPC. Pertanto, tutti questi meccanismi sono definiti dal sistema operativo host. POSIX definisce un ampio insieme di meccanismi IPC; Windows definisce un altro set; e altri sistemi definiscono le proprie varianti.

semafori

I semafori vengono utilizzati per sincronizzare le operazioni tra due o più processi. POSIX definisce due diversi set di funzioni semaforo:

  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() .

Questa sezione descrive i semafori IPC System V, così chiamati perché originati da Unix System V.

Innanzitutto, devi includere le intestazioni richieste. Le vecchie versioni di POSIX richiedevano #include <sys/types.h> ; POSIX moderno e la maggior parte dei sistemi non lo richiedono.

#include <sys/sem.h>

Quindi, dovrai definire una chiave sia nel genitore che nel bambino.

#define KEY 0x1111 

Questa chiave deve essere la stessa in entrambi i programmi o non si riferiscono alla stessa struttura IPC. Ci sono modi per generare una chiave concordata senza codificare il suo valore.

Successivamente, a seconda del compilatore, potrebbe essere necessario o meno eseguire questo passaggio: dichiarare un'unione ai fini delle operazioni del semaforo.

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

Quindi, definisci le strutture try ( semwait ) e raise ( semsignal ). I nomi P e V provengono dall'olandese

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

Ora, inizia prendendo l'id per il tuo semaforo 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 */
}

Nel genitore, inizializza il semaforo per avere un contatore di 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 */
}

Ora puoi decrementare o incrementare il semaforo di cui hai bisogno. All'inizio della tua sezione critica, decrementi il ​​contatore usando la funzione semop() :

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

Per incrementare il semaforo, usi &v invece di &p :

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

Nota che ogni funzione restituisce 0 in caso di successo e -1 in caso di fallimento. Non controllare questi stati di ritorno può causare problemi devastanti.


Esempio 1.1: Corse con discussioni

Il programma seguente avrà un fork processo e sia padre che figlio tenteranno di stampare caratteri sul terminale senza alcuna sincronizzazione.

#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);
        }
    }
}

Uscita (1a corsa):

aAABaBCbCbDDcEEcddeFFGGHHeffgghh

(2a corsa):

aabbccAABddBCeeCffgDDghEEhFFGGHH

Compilare ed eseguire questo programma dovrebbe darti un output diverso ogni volta.

Esempio 1.2: Evita le corse con i semafori

Modificando l' Esempio 1.1 per usare i semafori, abbiamo:

#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);
        }
    }
}

Produzione:

aabbAABBCCccddeeDDffEEFFGGHHgghh

Compilare ed eseguire questo programma ti darà la stessa uscita ogni volta.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow