C Language
Interprocess-kommunikation (IPC)
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:
- 'System V IPC' -
semctl()
,semop()
,semget()
. - '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.