PDA

View Full Version : [C e Linux] Problema con le pipe e le fork()


Corvo80
24-09-2005, 15:30
Salve a tutti, ho un problemino... Il seguente programma dovrebbe generare N processi figlio (nell'esempio N e'uguale a 2) e ciascuno di essi deve inviare separatamente al padre (che si occupa di gestire il servizio di stampa a video) due linee di testo del tipo "#x: linea 1" e "#x: linea 2", dove x e'l'identificativo del processo (da 1 a N). Tramite l'utilizzo dei semafori, si assicura che linee di diversi processi non possano essere stampati in maniera accavallata.

#include "pv.h" /* Struttura che definisce i semafori */
#include <stdlib.h>
#include <time.h>
#define N 2 /* Numero di processi, definire a piacere */
#define R 1 /* Numero di iterazioni per processo, definire a piacere */

int p(int semid); /* Funzione di accesso alla sezione critica */
int v(int semid); /* Funzione di uscita dalla sezione critica */
int initsem(key_t skey); /* Funzione di inizializzazione del semaforo */
void handlesem(key_t skey, int i, int outp); /* Funzione di gestione del semaforo */

struct msgst {
int proc; /* numero del processo */
int line; /* numero della riga da stampare */
};

main() {
key_t semkey = 0x200;
int i;
pid_t pid;
int p[2];

if(pipe(p)==-1) {
perror("pipe call");
exit(1);
}

for (i=1; i<=N; i++) { /* Crea N processi... */
pid=fork();
if (pid == 0) {
close(p[0]);
struct msgst dati_msg;
dati_msg.proc=i;
dati_msg.line=1;
handlesem(semkey, i, p[1]);
}
else if (pid > 0) {
/* Processo padre */
close(p[1]);
struct msgst valore_letto;
int j;
for (j=1; j<=N*R*2; j++) {
read(p[0],&valore_letto,sizeof(valore_letto));
printf("# %i: linea %i\n", valore_letto.proc, valore_letto.line);
}
}
else {
printf("Si e' verificato un errore nella chiamata a fork.\n"); /* ... ERRORE */
exit(2);
}
}
}

int initsem(key_t semkey) {
int status = 0, semid;

if((semid = semget(semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL)) == -1) { /* Crea un array di un semaforo e controlla che non si verifichino errori */
if(errno == EEXIST)
semid = semget(semkey, 1, 0);
}
else { /* Se tutto e'andato bene... */
semun arg;
arg.val = 1;
status = semctl(semid, 0, SETVAL, arg); /* Inizializza il semaforo a valore 1 */
}

if(semid == -1 || status == -1) { /* Gestisci eventuali errori */
perror("initsem fallita");
return (-1);
}

return semid;
}

void handlesem(key_t skey, int proc, int outp) {
int semid;
pid_t pid = getpid();

if((semid = initsem(skey)) < 0) /* Esci in caso di errore */
exit(1);

struct msgst dati_msg1;
dati_msg1.proc=proc;
dati_msg1.line=1;

struct msgst dati_msg2;
dati_msg2.proc=proc;
dati_msg2.line=2;

int j;
for (j = 1; j<=R; j++) { /* Ciascun processo ripete R volte... */
/* prima della sezione critica */
p(semid);
/* all interno della sezione critica */
write(outp,&dati_msg1,sizeof(dati_msg1)); /* Invia prima riga */
write(outp,&dati_msg2,sizeof(dati_msg2)); /* Invia seconda riga */
/* in procinto di abbandonare la sezione critica */
v(semid);
/* in procinto di terminare */
srandom(time(0)+proc);
sleep((int)random()%3+1); /* Dormi un tempo pseudocasuale */
}
exit(0); /* Fine */
}

int p(int semid) {
struct sembuf p_buf;
p_buf.sem_num = 0; /* Semaforo su cui effettuare l'operazione */
p_buf.sem_op = -1; /* valore negativo: forma generalizzata della funzione p() */
p_buf.sem_flg = SEM_UNDO; /* Valore predefinito */

if(semop(semid, &p_buf, 1) == -1) { /* Gestisci eventuali errori */
perror("p(semid) fallita");
exit(1);
}
return(0);
}

int v(int semid) {
struct sembuf v_buf;
v_buf.sem_num = 0; /* Semaforo su cui effettuare l'operazione */
v_buf.sem_op = 1; /* valore positivo: forma generalizzata della funzione v() */
v_buf.sem_flg = SEM_UNDO; /* Valore predefinito */

if(semop(semid, &v_buf, 1) == -1) { /* Gestisci eventuali errori */
perror("v(semid) fallita");
exit(1);
}
return(0);
}

Ecco il problema: dovrebbe risultare un output del tipo:

# 1: linea 1
# 1: linea 2
# 2: linea 1
# 2: linea 2

E invece risulta...

# 1: linea 1
# 1: linea 2
# 1: linea 2
# 1: linea 2
# 1: linea 2
# 1: linea 2
# 1: linea 2
# 1: linea 2

Dove sbaglio? Grazie della disponibilita'...

Corvo80
24-09-2005, 15:31
Mi sono dimenticato, questo e'il codice del file pv.h, necessario per far girare il programma...

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#define SEMPERM 0600
#define TRUE 1
#define FALSE 0

typedef union _semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;

Corvo80
26-09-2005, 08:19
Nebbia completa? :stordita:

Qu@ker
26-09-2005, 19:55
int main(void)
{
key_t semkey = 0x200;
int i, p[2];
pid_t pid;
struct msgst valore_letto;

if (pipe(p) == -1) {
perror("pipe call");
exit(1);
}
for (i = 0; i < N; i++) { /* Crea N processi... */
pid = fork();
if (pid < 0) {
perror("fork call");
exit(1);
}
if (pid == 0) {
struct msgst dati_msg;

close(p[0]);
dati_msg.proc = i;
dati_msg.line = 1;
handlesem(semkey, i, p[1]);
_exit(0);
}
}
/* Processo padre */
close(p[1]);
for (i = 0; i < N * R * 2; i++) {
read(p[0], &valore_letto, sizeof(valore_letto));
printf("# %i: linea %i\n", valore_letto.proc,
valore_letto.line);
}
return 0;
}

Ricordati di togliere l'exit() da handlesem().

ilsensine
27-09-2005, 08:25
Se avessi controllato i valori di ritorno delle write e della read forse ci saresti arrivato da solo.
nb non vedo l'utilità del semaforo in questo contesto (e tra l'altro lo utilizzi in maniera errata, ad una prima occhiata)
--- a.c.org 2005-09-27 09:32:18.000000000 +0200
+++ a.c 2005-09-27 09:32:50.000000000 +0200
@@ -36,10 +36,9 @@ main() {
}
else if (pid > 0) {
/* Processo padre */
- close(p[1]);
struct msgst valore_letto;
int j;
- for (j=1; j<=N*R*2; j++) {
+ for (j=1; j<=R*2; j++) {
read(p[0],&valore_letto,sizeof(valore_letto));
printf("# %i: linea %i\n", valore_letto.proc, valore_letto.line);
}