|
|
Synchronisation mit SemaphorenSemaphoren gehen auf den Informatiker E. W. Dijkstra zurück. Sie dienen als Schutz gegen gleichzeitiges Operieren in einem kritischen Bereich. Wenn beispielsweise der gemeinsame Speicher (Shared Memory) von zwei oder mehr Prozessen gleichzeitig genutzt wird, muss verhindert werden, dass sie gleichzeitig schreiben oder dass ein Prozess liest, während ein anderer Prozess schreibt. Das Erzeugen einer Semaphore erfolgt analog zum Erzeugen des Shared Memory. Selbst die Konstante IPC_CREAT ist identisch.
#include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); Der Parameter key ist wie bei Shared Memory eine Zahl, die von den Programmen vereinbart wird, die über die Semaphore kommunizieren wollen. Im zweiten Parameter wird angegeben, wieviele Semaphoren erzeugt werden sollen.
Der letzte Parameter enthält
die Berechtigung, wie man sie von Der Rückgabewert ist die Semaphoren-ID, die für die Identifikation benötigt wird. Scheiterte der Aufruf, gibt er -1 zurück.
Die Semaphoren werden mit dem Aufruf von
#include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf *sops, unsigned anzahl);
Als Parameter semid wird der Rückgabewert von Die Struktur sembuf beinhaltet die folgenden Felder:
struct sembuf { short sem_num; /* semaphore number: 0 = first */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }; sem_num gibt an, welche Semaphore des Semaphorensets gemeint ist. Die Zählung beginnt bei 0. sem_flag kann die Optionen IPC_NOWAIT und SEM_UNDO annehmen. SEM_UNDO bewirkt, dass die Operation bei Ende des Prozesses zurückgenommen wird.
Der Systemaufruf Die Variable sem_op der Struktur sembuf bestimmt die Operation.
#include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int kommando, union semun arg); Der Parameter kommando gibt an, welche Operation ausgeführt wird. Das wichtigste Kommando ist IPC_RMID. Es zerstört sofort alle Semaphoren dieses Semaphorensets. Die auf die Semaphoren wartenden Prozesse werden geweckt und erhalten einen Fehler als Rückgabewert ihres Funktionsaufrufs.
BeispielDas Programm sem erzeugt eine Semaphore, sofern nicht schon eine existiert, und wartet auf die Returntaste. Anschließend setzt sie die Semaphore. Das führt zum Blockieren oder das Programm betritt den kritischen Bereich. Das wird am Bildschirm angezeigt. Nach erneutem Drücken der Returntaste verlässt das Programm wieder den kritischen Bereich und gibt ihn für andere frei. Zum Testen können Sie das Programm auf mehreren Terminals oder Fenstern starten und sie nacheinander in den kritischen Bereich gehen lassen.
[Semaphoren sem.c] #include <sys/ipc.h> #include <sys/sem.h>
int main(int argc, char **argv) { int semID; struct sembuf sema;
/* Semaphore erzeugen */ semID = semget(2404, 1, IPC_CREAT | 0666); if (semID >= 0) { puts("Semaphore erzeugt. Vor Anfrage"); getchar(); /* Bereite die Semaphore vor und starte */ sema.sem_num = 0; sema.sem_flg = SEM_UNDO; sema.sem_op = -1; if (-1==semop(semID, &sema, 1)) { /* Fehler */ perror("semop"); } puts("bin im kritischen Bereich"); getchar(); sema.sem_op = 1; if (-1==semop(semID, &sema, 1)) { /* Fehler */ perror("semop"); } puts("und nun wieder draußen"); } else { perror("semget"); } } Auch die Semaphore bleibt nach Verlassen des Programms bestehen und muss explizit gelöscht werden. Dazu reicht das folgende Programmbeispiel aus:
[Semaphoren destroy.c] #include <sys/ipc.h> #include <sys/shm.h>
int main(int argc, char **argv) { int semID; char *myPtr; int i;
semID = semget(2404, 1, 0666); if (semID >= 0) { /* zerstöre die Semaphore */ semctl(semID, 1, IPC_RMID, 0); } else { /* semctl lief schief */ perror("semget"); } }
Die Semaphore bleibt solange erhalten, bis ein Programm in explizit
entfernt (s. o.), bis zum nächsten Shutdown oder bis er mit dem Befehl
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|