Sök…


Introduktion

IPC-mekanismer mellan processer tillåter olika oberoende processer att kommunicera med varandra. Standard C tillhandahåller inga IPC-mekanismer. Därför definieras alla sådana mekanismer av värdoperativsystemet. POSIX definierar en omfattande uppsättning IPC-mekanismer; Windows definierar en annan uppsättning; och andra system definierar sina egna varianter.

semaforer

Semaforer används för att synkronisera operationer mellan två eller flera processer. POSIX definierar två olika uppsättningar av semaforfunktioner:

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

Det här avsnittet beskriver System V IPC semaforer, så kallade eftersom de har sitt ursprung i Unix System V.

Först måste du ta med de rubriker som krävs. Gamla versioner av POSIX krävs #include <sys/types.h> ; moderna POSIX och de flesta system kräver det inte.

#include <sys/sem.h>

Då måste du definiera en nyckel i såväl förälder som barn.

#define KEY 0x1111 

Den här nyckeln måste vara densamma i båda programmen, annars kommer de inte att referera till samma IPC-struktur. Det finns sätt att generera en överenskommen nyckel utan att hårdkoda dess värde.

Beroende på din kompilator kan du eller inte behöva göra det här steget: förklara en fackförening för semaforoperationer.

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

Definiera därefter dina försök ( semwait ) och höja ( semsignal ) strukturer. Namnen P och V kommer från nederländska

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

Börja nu med att få id för din IPC-semafor.

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

Initiera semaforen för föräldern för att ha en räknare på 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 */
}

Nu kan du minska eller öka semaforen som du behöver. I början av ditt kritiska avsnitt, minskar du räknaren med semop() :

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

För att öka semaforen använder du &v istället för &p :

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

Observera att varje funktion returnerar 0 på framgång och -1 vid misslyckande. Att inte kontrollera dessa returtillstånd kan orsaka förödande problem.


Exempel 1.1: Racing med trådar

Nedanstående program kommer att ha en process fork barn och både föräldrar och barn försök att skriva ut tecken på anslutnings utan synkronisering.

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

Utgång (1: a körning):

aAABaBCbCbDDcEEcddeFFGGHHeffgghh

(2: a körning):

aabbccAABddBCeeCffgDDghEEhFFGGHH

Att sammanställa och köra detta program bör ge dig en annan utgång varje gång.

Exempel 1.2: Undvik att tävla med semaforer

Att ändra exempel 1.1 för att använda semaforer har vi:

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

Produktion:

aabbAABBCCccddeeDDffEEFFGGHHgghh

Att sammanställa och köra detta program ger dig samma utgång varje gång.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow