PDA

View Full Version : Linux, C e semafori: dove sbaglio??


cn73
01-04-2004, 22:42
Olevo provare a risolvere il calssico problema di IPC del Produttore e Consumatore con buffer limitato (nel mio caso 4 elementi)...
Ho scritto questo codice, ma non funziona :( Dove sbaglio?? E' tutta la sera che ci sbatto la testa!



#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>

#define ARRAY_LENGTH 2
#define BUF_DIM 4


main() {

int f;
int in=0,out=0;
int empty,full;
char nextp,nextc;
struct sembuf sops[ARRAY_LENGTH];
int semid;

//char buffer[10];
//char *pun;

semid = semget(IPC_PRIVATE,ARRAY_LENGTH,0666); //4 semafori nel set, r/w x tutti!
printf("prelevato set di semafori id = %d\n",semid);

empty = semctl(semid,0,SETVAL,BUF_DIM);
full = semctl(semid,1,SETVAL,0);

printf("Valore iniziale dei semafori:\n");
printf("EMPTY: %d\n",semctl(semid,0,GETVAL,0));
printf("FULL: %d\n",semctl(semid,1,GETVAL,0));


f = fork();
if (f == -1)
{
fprintf(stderr,"fork fallita\n");
exit(1);
}

else if (f !=0) { //P

while (1){
//nextp = 'x';
printf("\n(P) -- wait(empty) -- tento di decrementare il semaforo EMPTY %d\n",semctl(semid,0,GETVAL,0));
//wait(empty) se il valore del sem EMPTY è 0 nn mi fa andare avanti!!
sops[0].sem_num = 0; /* operazione sul semaforo 1 */
sops[0].sem_op = -1; /* decrementa il semaforo di 1 */
sops[0].sem_flg = 0; /* che fare: wait se == 0 */

empty = semop(semid,sops,1); //1: lunghezza dell'array sops

printf("\n(P) ho decrementato il semaforo EMPTY: %d\n", semctl(semid,0,GETVAL,0));
//buffer[in]= nextp;
system("sleep 10"); //P + lento di C
printf("\n(P) ho prodotto l'elemento %d\n", in);


in = (in +1) % BUF_DIM;

printf("\n(P) -- signal(empty) -- tento di incrementare il semaforo FULL %d\n",semctl(semid,1,GETVAL,0));
//signal(full) incremento FULL
sops[1].sem_num = 1; /* operazione sul semaforo 2 */
sops[1].sem_op = 1; /* incrementa semaforo 2*/
sops[1].sem_flg = 0; /* che fare: ??*/
full = semop(semid,sops,1);
printf("\n(P) - ho incrementato il semaforo FULL: %d\n" , semctl(semid,1,GETVAL,0));



}
exit(0);
//semctl(semid,IPC_RMID,0);
//printf("(P) Rilasciato i sem, ora muoio... \n");


}
else { //C

while (1){

printf("\n(C) -- wait(full) -- tento di decrementare il semaforo FULL: %d\n",semctl(semid,1,GETVAL,0));
//wait(full)
sops[1].sem_num = 1; /* operazione sul semaforo 0 */
sops[1].sem_op =-1; /* decrementa il semaforo di 1 */
sops[1].sem_flg = 0; /* che fare: wait se semaforo = 0 */

full = semop(semid,sops,1); //1: lunghezza dell'array sops
printf("\n(C) ho decrementato il semaforo FULL: %d\n" , semctl(semid,1,GETVAL,0));
//nextc=buffer[out];
system("sleep 1");
printf("\n(C) ho consumato l'elemento %d\n", out);
out = (out +1) % BUF_DIM;

printf("\n(C) -- signal(empty) -- tento di incrementare il semaforo EMPTY - signal(EMPTY) %d\n" , semctl(semid,0,GETVAL,0));
//signal(empty)
sops[0].sem_num = 0; /* operazione sul semaforo 0 */
sops[0].sem_op = 1; /* incrementa il semaforo di 1 */
sops[0].sem_flg = 0; /* che fare: ?? */
empty = semop(semid,sops,1);
printf("\n(C) -ho incrementato il semaforo EMPTY - signal(EMPTY) %d\n" , semctl(semid,0,GETVAL,0));

}

}

}

ilsensine
02-04-2004, 07:52
--- sem.c.org 2004-04-02 09:03:57.000000000 +0200
+++ sem.c 2004-04-02 09:03:31.000000000 +0200
@@ -62,7 +62,7 @@
sops[1].sem_num = 1; /* operazione sul semaforo 2 */
sops[1].sem_op = 1; /* incrementa semaforo 2*/
sops[1].sem_flg = 0; /* che fare: ??*/
- full = semop(semid,sops,1);
+ full = semop(semid,sops+1,1);
printf("\n(P) - ho incrementato il semaforo FULL: %d\n" , semctl(semid,1,GETVAL,0));


@@ -84,7 +84,7 @@
sops[1].sem_op =-1; /* decrementa il semaforo di 1 */
sops[1].sem_flg = 0; /* che fare: wait se semaforo = 0 */

- full = semop(semid,sops,1); //1: lunghezza dell'array sops
+ full = semop(semid,sops+1,1); //1: lunghezza dell'array sops
printf("\n(C) ho decrementato il semaforo FULL: %d\n" , semctl(semid,1,GETVAL,0));
//nextc=buffer[out];
system("sleep 1");

cn73
02-04-2004, 08:48
Per cortesia fammi capire...

intendi togliere per il semaforo FULL

- full = semop(semid,sops,1);

e sostituirlo con

+ full = semop(semid,sops+1,1); ??


Io avevo capito questo:


La chiamata semop() consente di specificare una lista (sops[]) di
(nsops) operazioni:
int semop ( int semid, struct sembuf *sops, unsigned nsops );

Un esempio di chiamata e':
semop ( sid, sops, 1);
la quale indica che si fa una operazione, la quale e' specificata
nella lista sops[].

quel parametro nsops pensavo fosse l'offset all'inerno dell'array a partrire da sops...

ilsensine
02-04-2004, 09:06
Originariamente inviato da cn73
Per cortesia fammi capire...

intendi togliere per il semaforo FULL

- full = semop(semid,sops,1);

e sostituirlo con

+ full = semop(semid,sops+1,1); ??


Io avevo capito questo:


man diff ;)


quel parametro nsops pensavo fosse l'offset all'inerno dell'array a partrire da sops...
Puoi specificare in un array _più_ operazioni da compiere anche su _più_ semafori in maniera _atomica_.
Nel tuo caso compi una unica operazione su un unico semaforo alla volta, quindi potevi anche non usare un array.

cn73
02-04-2004, 09:44
full = semop(semid,sops+1,1);


sops +1 è l'indirizzo dell'elemento dell'array che contiene il semaforo sul quale voglio aplllicare l'operazione?

il terzo parametro (nops =1) che cavolo indica? :D Che voglio eseguire una sola operazione atomica su quel array di semafori?

cn73
02-04-2004, 11:23
Per non riscrivere sempre il codice dei semafori è corretto implementare due funzioni P e V in questo modo?


P(struct sembuf sems[ARRAY_LENGTH], int index, int semid){
sems[index].sem_num = index; /* operazione sul semaforo 0 */
sems[index].sem_op = -1; /* incrementa il semaforo di 1 */
sems[index].sem_flg = 0; /* che fare: ?? */

return semop(semid,sems + index,1);
}

V(struct sembuf sems[ARRAY_LENGTH], int index, int semid){
sems[index].sem_num = index; /* operazione sul semaforo 0 */
sems[index].sem_op = +1; /* incrementa il semaforo di 1 */
sems[index].sem_flg = 0; /* che fare: ?? */

return semop(semid,sems + index,1);
}

ilsensine
02-04-2004, 12:00
Ti stai solo complicando la vita...

struct sembuf s;
s.sem_flg = 0;

s.sem_op = -1;
s.sem_num = 0;
semop(semid, &s, 1);

s.sem_op = 1;
s.sem_num = 1;
semop(semid, &s, 1);

cn73
02-04-2004, 13:33
Allora diciamo che un array di semafori è utile quando si devono eseguire operazioni unuitarie contemporaneamente su + semafori.Se devo eseguire una sola operazion alla volta su n semafori conviene definire 2 diversi semafori:


struct sembuf s1;
struct sembuf s2;

E' corretto?

ilsensine
02-04-2004, 13:58
Se le operazioni non vengono effettuate in contemporanea (ad es. da due thread) puoi anche usare una unica struct sembuf

cn73
02-04-2004, 16:14
Ho capito!


struct sembuf sops;

...
prelevo n semafori
semid = semget(IPC_PRIVATE,n,0666);

e poi uso P(i) e V(i) dove


P(int sem ){
sops.sem_num = sem; /* operazione sul semaforo 0 */
sops.sem_op = -1; /* incrementa il semaforo di 1 */
sops.sem_flg = 0; /* che fare: ?? */

return semop(semid,sops,1);
}

V(int sem){
sops.sem_num = sem; /* operazione sul semaforo 0 */
sops.sem_op = +1; /* incrementa il semaforo di 1 */
sops.sem_flg = 0; /* che fare: ?? */

return semop(semid,sops ,1);
}