PDA

View Full Version : [C] Segmentation fault su memoria condivisa


VegetaSSJ5
12-07-2004, 16:08
Salve a tutti, ormai sto infestando questa sezione con i miei post ma non so a chi altro rivolgermi per dei chiarimenti quindi... sopportatemi;)
Veniamo al dunque, il programma seguente si compila correttamente ma mi dà un segmentation fault a tempo d'esecuzione. In pratica io voglio creare un segmento di memoria condivisa da utilizzare come un array (in modo tale che possano accedervi il processo padre e i processi figli) ma mi dà quell'errore lì. Qualcuno può dirmi come mai? grazie#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>

int *automobili;
int *direzione;

int main (int argc, char* argv[]) {
int autom, direz, N;
N=10;
if (autom=shmget(IPC_PRIVATE, N*sizeof(pid_t), 0666) <0) perror("Errore nella creazione del segmento di memoria condivisa 'automobili'");
automobili=(int *) shmat (autom, 0, SHM_RND);
if (direz=shmget(IPC_PRIVATE, N*sizeof(int), 0666) <0) perror("Errore nella creazione del segmento di memoria condivisa 'direzione'");
direzione=(int *) shmat (direz, 0, SHM_RND);
automobili[0]=3;
automobili[1]=getpid();
printf("%d %d", automobili[0], automobili[1]);
}

ilsensine
12-07-2004, 16:15
Nulla di grave, il classico problema hardware tra la sedia e la tastiera :D

--- segfault.c.org 2004-07-12 17:29:06.000000000 +0200
+++ segfault.c 2004-07-12 17:29:40.000000000 +0200
@@ -14,9 +14,9 @@
int main (int argc, char* argv[]) {
int autom, direz, N;
N=10;
- if (autom=shmget(IPC_PRIVATE, N*sizeof(pid_t), 0666) <0) perror("Errore nella creazione del segmento di memoria condivisa 'automobili'");
+ if ((autom=shmget(IPC_PRIVATE, N*sizeof(pid_t), 0666)) <0) perror("Errore nella creazione del segmento di memoria condivisa 'automobili'");
automobili=(int *) shmat (autom, 0, SHM_RND);
- if (direz=shmget(IPC_PRIVATE, N*sizeof(int), 0666) <0) perror("Errore nella creazione del segmento di memoria condivisa 'direzione'");
+ if ((direz=shmget(IPC_PRIVATE, N*sizeof(int), 0666)) <0) perror("Errore nella creazione del segmento di memoria condivisa 'direzione'");
direzione=(int *) shmat (direz, 0, SHM_RND);
automobili[0]=3;
automobili[1]=getpid();

ilsensine
12-07-2004, 16:16
nb non compilate MAI con -Wall, mi raccomando ;)

VegetaSSJ5
12-07-2004, 16:49
grazie ilsensine! cmq il problema non ero io ma l'editor kate che mi segnava come ultima parentesi quella che tu poi hai aggiunto;)
come mai non bisogna mai compilare com -Wall??

ilsensine
12-07-2004, 16:57
Originariamente inviato da VegetaSSJ5
come mai non bisogna mai compilare com -Wall??
Era una nota ironica. Se compilavi con -Wall, il compilatore ti avrebbe segnalato che c'era qualcosa di sospetto.
Io compilo _sempre_ con -Wall (e per la produzione con -Wall -Werror).

VegetaSSJ5
13-07-2004, 13:44
ilsensine ti ringrazio molto, sei il mio angelo custode, tuttavia ci sono per me dei misteri inspiegabili tipo il seguente: il padre stampa il valore giusto di automobili[i] invece il figlio no#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>

int *automobili;
int *direzione;

void funzione (int N);

int main (int argc, char* argv[]) {
int autom, direz, N;
N=10;
if ((autom=shmget(IPC_PRIVATE, N*sizeof(pid_t), 0666)) <0) perror("Errore");
automobili=(int *) shmat (autom, 0, SHM_RND);
if ((direz=shmget(IPC_PRIVATE, N*sizeof(int), 0666)) <0) perror("Errore");
direzione=(int *) shmat (direz, 0, SHM_RND);
funzione(3);
}

void funzione (int N) {
int i;
pid_t padre=getpid();
for (i=0; i<N; i++) {
if (getpid()==padre) {
if ((automobili[i]=(int)fork()) < 0) perror("Errore generando l'automobile");
if (getpid()==padre) printf("\nPADRE, automobili[%d]= %d\n\n", i, automobili[i]);
}
if (getpid()!=padre) {
printf("\nAUTO %d, automobili[%d]= %d", i, i, automobili[i]);
i=N;
}
}
}se invece sostituisco il ciclo for con quest'altro tutto funziona correttamentefor (i=0; i<N; i++) {
pid_t pid=fork();
if (pid==0) printf("figlio %d dopo fork %d %d\n", i, automobili[0], automobili[1]);
else printf("padre dopo fork %d %d\n", automobili[0], automobili[1]);
if (pid==0) {
automobili[0]=140;
automobili[1]=(int)getpid();
printf("Figlio %d dopo assegnamento %d %d\n", i, automobili[0], automobili[1]);
}
else {
printf("padre dopo assegnamento %d %d\n", automobili[0], automobili[1]);
automobili[0]=111;
automobili[1]=(int)getpid();
printf("padre dopo riassegnamento %d %d\n", automobili[0], automobili[1]);
}
if (pid==0) {
sleep(1);
printf("figlio %d dopo riassegnamento %d %d\n", i, automobili[0], automobili[1]);
i=N;
}
}
}:cry:

ilsensine
13-07-2004, 14:13
if (getpid()==padre) {
if ((automobili[i]=(int)fork()) < 0) perror("Errore generando l'automobile");
if (getpid()==padre) printf("\nPADRE, automobili[%d]= %d\n\n", i, automobili[i]);
}
if (getpid()!=padre) {
printf("\nAUTO %d, automobili[%d]= %d", i, i, automobili[i]);
i=N;
}

Hint: hai almeno 2 race condition in questo codice...una è veramente mastodontica, la seconda più subdola.

ilsensine
13-07-2004, 14:18
--- race.c.org 2004-07-13 15:26:25.000000000 +0200
+++ race.c 2004-07-13 15:33:06.000000000 +0200
@@ -6,6 +6,7 @@
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <sched.h>

int *automobili;
int *direzione;
@@ -24,10 +25,13 @@

void funzione (int N) {
int i;
+ pid_t val;
pid_t padre=getpid();
for (i=0; i<N; i++) {
if (getpid()==padre) {
- if ((automobili[i]=(int)fork()) < 0) perror("Errore generando l'automobile");
+ if((val = fork())<0) perror("fork");
+ if(val) automobili[i] = val; // Fix prima race
+ else sched_yield(); // Fix seconda race!!
if (getpid()==padre) printf("\nPADRE, automobili[%d]= %d\n\n", i, automobili[i]);
}
if (getpid()!=padre) {

La seconda race potrebbe o meno occorrere, a seconda dello scheduler e del kernel (è veramente subdola). Lo sched_yield ti pone al sicuro.

VegetaSSJ5
13-07-2004, 18:06
grazie ilsensine.
puoi dirmi cosa sono le race condition? che cosa fa la funzione sched_yeld?

VegetaSSJ5
13-07-2004, 19:04
allora mi sono informato (google;))

race condition:
"Le race condition sono gli errori piu' comuni nella programmazione
multithreaded o multiprocesso. Una race condition si verifica quando
una assunzione fatta dal programmatore che non dovrebbe cambiare per un
dato lasso di tempo, cambia per forza...."
fonte (http://www.sys-net.it/pipermail/sviluppo/2004-April/000290.html)

sched_yield():
pone il processo chiamante allo stato READY.

puoi dirmi quali sono le race condition nel mio caso? quale utilità può avere porre il processo figlio allo stato ready?

ilsensine
13-07-2004, 19:48
Quando invochi la fork, normalmente il controllo passa al neonato processo child. Non c'è una regola per stabilire chi deve continuare (padre o figlio), ma su linux normalmente si preferisce così. Se questo accade, il figlio continua mentre la fork del padre non è ancora ritornata (in quanto il controllo è passato al figlio). Il figlio quindi continua per la sua strada e...legge automobili[i].

>> Domanda: se il fork del padre ancora non è ritornato, cosa c'è dentro automobili[i]? :D <<

sched_yield è documentato nelle pagine man, che ti consiglio di leggere ;)

VegetaSSJ5
14-07-2004, 12:48
Originariamente inviato da ilsensine
Quando invochi la fork, normalmente il controllo passa al neonato processo child. Non c'è una regola per stabilire chi deve continuare (padre o figlio), ma su linux normalmente si preferisce così. Se questo accade, il figlio continua mentre la fork del padre non è ancora ritornata (in quanto il controllo è passato al figlio). Il figlio quindi continua per la sua strada e...legge automobili[i].

>> Domanda: se il fork del padre ancora non è ritornato, cosa c'è dentro automobili[i]? :D <<

sched_yield è documentato nelle pagine man, che ti consiglio di leggere ;)
:doh:
:idea: sei mitico ilsensine! :mano: