Suche…


Einführung

Interprozesskommunikationsmechanismen (IPC) ermöglichen die Kommunikation verschiedener unabhängiger Prozesse miteinander. Standard C bietet keine IPC-Mechanismen. Daher werden alle derartigen Mechanismen vom Host-Betriebssystem definiert. POSIX definiert einen umfangreichen Satz von IPC-Mechanismen. Windows definiert ein anderes Set. und andere Systeme definieren ihre eigenen Varianten.

Semaphore

Semaphore werden verwendet, um Vorgänge zwischen zwei oder mehr Prozessen zu synchronisieren. POSIX definiert zwei verschiedene Sätze von Semaphorfunktionen:

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

In diesem Abschnitt werden die System V-IPC-Semaphore beschrieben, die so genannt werden, weil sie aus Unix System V stammen.

Zuerst müssen Sie die erforderlichen Header angeben. Alte Versionen von POSIX erforderten #include <sys/types.h> ; moderne POSIX und die meisten Systeme benötigen dies nicht.

#include <sys/sem.h>

Dann müssen Sie einen Schlüssel sowohl im übergeordneten Element als auch im untergeordneten Element definieren.

#define KEY 0x1111 

Dieser Schlüssel muss in beiden Programmen gleich sein, da sie sich nicht auf dieselbe IPC-Struktur beziehen. Es gibt Möglichkeiten, einen vereinbarten Schlüssel zu generieren, ohne dessen Wert fest zu codieren.

Als Nächstes müssen Sie diesen Schritt je nach Compiler möglicherweise nicht ausführen: Deklaration einer Union für Semaphoroperationen.

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

Als nächstes definieren Sie Ihre try ( semwait ) und (erhöhen semsignal ) Strukturen. Die Namen P und V stammen aus dem Niederländischen

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

Holen Sie sich zunächst die ID für Ihr IPC-Semaphor.

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 */
}

Initialisieren Sie das Semaphor im übergeordneten Element mit einem Zähler von 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 */
}

Jetzt können Sie das Semaphor nach Bedarf dekrementieren oder erhöhen. Zu Beginn Ihres kritischen Abschnitts dekrementieren Sie den Zähler mit der Funktion semop() :

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

Um das Semaphor zu inkrementieren, verwenden Sie &v anstelle von &p :

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

Beachten Sie, dass jede Funktion bei Erfolg 0 und bei Fehler -1 zurückgibt. Wenn diese Rückgabestatus nicht geprüft werden, kann dies zu verheerenden Problemen führen.


Beispiel 1.1: Rennen mit Fäden

Das untenstehende Programm hat einen Prozesszweig für ein fork Element, und Eltern und Kinder versuchen, Zeichen ohne Synchronisation auf das Terminal zu drucken.

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

Ausgabe (1. Lauf):

aAABaBCbCbDDcEEcddeFFGGHHeffgghh

(2. Lauf):

aabbccAABddBCeeCffgDDghEEhFFGGHH

Beim Kompilieren und Ausführen dieses Programms sollten Sie jedes Mal eine andere Ausgabe erhalten.

Beispiel 1.2: Vermeiden Sie das Rennen mit Semaphoren

Wenn Sie Beispiel 1.1 für die Verwendung von Semaphoren modifizieren, haben wir:

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

Ausgabe:

aabbAABBCCccddeeDDffEEFFGGHHgghh

Wenn Sie dieses Programm kompilieren und ausführen, erhalten Sie jedes Mal dieselbe Ausgabe.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow