Visualizzazione dei risultati da 1 a 5 su 5
  1. #1
    Utente di HTML.it L'avatar di leaf
    Registrato dal
    Oct 2012
    Messaggi
    316

    [C], sistemi operativi: fork, memoria condivisa e semafori

    ciao a tutti, devo fare un esercizio di sistemi operativi. questa più o meno è la consegna:

    da riga di comando si hanno n figli (argv[1]) che lavorano su una variabile m(argv[0]).
    il padre genera i n figli e crea il segmento di memoria condivisa. poi aspetta che i figli terminino l'operazione.
    i figli lavorano con un semaforo per modificare la variabile m che dev'essere scritta nella memoria condivisa.
    quando i figli terminano, il padre stampa il valore della variabile contenuta nella memoria condivisa


    questo è il mio codice:
    codice:
    #include <semaphore.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/shm.h>
    #include <sys/stat.h>
    
    
    int m; //mia variabile condivisa
    
    int main(int argc, char *argv[])
    {
    	int segment_id;
    	int j;
    	int size = 4096;
    	sem_t *sem;
    	char *shared_memory;
    	pid_t pid;
    
    /* costruisce un segmento condiviso – padre e figlio condivideranno "sid" */
    	segment_id = shmget( IPC_PRIVATE, size, S_IRUSR | S_IWUSR );
    
    	if ( segment_id < 0 ) { // DEBUG
    	printf("shared memory initilization failed\n");
    	return 1;
    	}
    
    /* inizializza il semaforo */
    	sem = sem_init(&sem, 0, 1 );
    	
    	if ( !sem ) { // DEBUG
    		printf("error semaphore initilization\n");
    		return 1;
    	}
    
    /* il padre attacca il segmento al suo spazio di indirizzi */
    	shared_memory = (char *)shmat( segment_id, NULL, 0 );
    
    /* inizializzo m */
    	m = atoi(argv[0]);
    
    	for (int x=0;x<atoi(argv[1]);x++){  // creo n figli (n = atoi(argv[1]))
    		pid = fork();
    
    		if ( pid < 0 ) { // DEBUG
    			printf("fork failed\n");
    			return 1;
    		}
    	}
    
    	if (pid>0)  // PADRE
    		wait(NULL); // aspetta figli
                    printf("valore: %s\n", m); //stampa il valore finale della variabile
    
    
    /* il figlio deve attacca il segmento al *suo* spazio di indirizzi */
    	if ( pid == 0 ) {
    		shared_memory = (char *)shmat( segment_id, NULL, 0 );
    
    	        do {
    		        sem_wait( sema ); /* entro nella sezione critica */
    		
    		        if (m%2 != 0)   //modifica variabile
    			        m*=2;
    		        else
    			        m-=1;
    
    		// memorizzo il valore di m nella memoria
    		        sprintf(shared_memory, m);
    
    		        sem_post( sema ); /* esco dalla sezione critica */
    	         } while(1);
            }
    
    
    
    /* padre e figlio scollegano il segmento */
    	shmdt(shared_memory);
    
    /* il padre rimuove il semaforo ed il segmento */
    	if ( pid > 0 ) {
    		sem_delete(&sem);
    		shmctl(segment_id, IPC_RMID, 0 );
    	}
    
    	return 0;
    }


    ora, i miei dubbi riguardano sostanzialmente il come dichiarare la variabile m e come far sì che essa sia memorizzata nella memoria condivisa. è giusto come l'ho scritto io?

    grazie in anticipo,

    L.

  2. #2
    Nel tuo codice sia il semaforo che m sono variabili locali ai singoli processi, non c'è alcuna condivisione - ti limiti a creare la memoria condivisa ma non ci fai niente.

    Per fare quello che chiedi, devi creare sia m che il semaforo come puntatori, e farli puntare all'interno dell'area di memoria condivisa (occhio che tra l'altro il secondo parametro di sem_init deve essere 1 per semafori condivisi tra processi).
    Tra l'altro, tutto sommato conviene creare e agganciare il segmento di memoria condivisa prima della fork, tanto le "view" del segmento condiviso sono ereditate dai processi figli.
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it L'avatar di leaf
    Registrato dal
    Oct 2012
    Messaggi
    316
    Grazie,
    durante la scorsa nottata ho modificato il codice e sono arrivato quasi alla soluzione (credo). ho usato una struttura che contenga semaforo e variabile m e ci accedo tramite puntatore.

    Tra l'altro, tutto sommato conviene creare e agganciare il segmento di memoria condivisa prima della fork, tanto le "view" del segmento condiviso sono ereditate dai processi figli.
    sei sicuro di questo? perchè in un codice di un mio professore ho visto che ha esplicitamente agganciato sia padre che figlio separatamente, ed ero convinto che i figli non ereditassero l'area condivisa..

    codice:
        #include <stdio.h>
        #include <unistd.h>
        #include <stdlib.h>
        #include <sys/shm.h>
        #include <semaphore.h>
    
        struct shared {  // shared structure
    	   sem_t sem;
    	   int m;
        };
    
        void error(char *msg) {  // debug function
    	    pritnf("%s error.\n");
    	    return 1;
        }
    
        int main(int argc, char *argv[]) {
    
    	    int sid;    // segment id
    	    struct shared *data;    
    	    pid_t pid;
    
    	    if(argc<3) error("argc");
    	
    	    if(argv[1]<0) error("argv");
      
    	    if(sid = shmget(IPC_PRIVATE, sizeof(shared *data),0666)<0) error("sid-shmget"); // father create sid
    
    	    if(data = (struct shared*) shmat(sid,(void *)0,1)<0) error("data-shmat"); // father allocate structure into his address scope
    
    	    data.m = argv[2]; // father initialize m
    	
    	    if(sem_init(&data.sem)<0) error("sem_init"); // father initialize semaphore
    
    	    for (int i=0; i<atoi(argv[1]);i++) {  // create sons
    		    if((pid = fork())<0) error("fork");
    	    }
    
    	    if (pid>0) {  // father
    		    wait(NULL);  // wait for sons
    		    sem_wait(&data.sem);  // entry section
    		    printf("valore: %d\n", data.m);
    		    sem_post(&data.sem);  // exit section
    	
    	    } else {  // son
    		    if(data = (struct shared*) shmat(sid,(void *)0,1)<0) error("shmat"); // son allocate data into his address scope
    		
    		    sem_wait(data.sem); // entry section
    		    
                        if (data.m%2 != 0) data.m*=2;  // modify variable
    		    else data.m-=1;
    		
                        sem_post(&data.m);  // exit section
    	        }
    
    	    shmdt(&data); // father and sons deallocate data
    
    	    if (pid>0) {  // father delete semaphore and sid
    		    sem_delete(&data.sem);
    		    shmctl(sid,IPC_RMID,0);
    	    }
    
        return 0;
        }
    grazie ancora!

    L.

  4. #4
    Originariamente inviato da leaf
    Grazie,
    durante la scorsa nottata ho modificato il codice e sono arrivato quasi alla soluzione (credo). ho usato una struttura che contenga semaforo e variabile m e ci accedo tramite puntatore.
    Sì, è la soluzione migliore.
    sei sicuro di questo? perchè in un codice di un mio professore ho visto che ha esplicitamente agganciato sia padre che figlio separatamente, ed ero convinto che i figli non ereditassero l'area condivisa..
    L'avevo letto ieri nella manpage di sem_init:
    If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent's memory mappings, it can also access the semaphore.) Any process that can access the shared memory region can operate on the semaphore using sem_post(3), sem_wait(3), etc.
    La cosa poi è confermata dalla manpage di fork, dove, tra le eccezioni relative alla clonazione del processo, non vengono citati i segmenti di memoria condivisi.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it L'avatar di leaf
    Registrato dal
    Oct 2012
    Messaggi
    316
    ottimo ti ringrazio! il codice che ho riformulato è corretto? inoltre, altro dubbio: se io la parte di padre e figlio la scrivo direttamente dentro al ciclo for, in teoria poichè i figli sono creati uno alla volta il semaforo non mi serve più giusto? sto dicendo di fare così:

    codice:
    for (int i=0; i<atoi(argv[1]);i++) {  // create sons
    	if((pid = fork())<0) error("fork");
    
    	if (pid>0) {  // father
    		wait(NULL);  // wait for sons
    	
    	} else {  // son
    		if(data = (struct shared*) shmat(sid,(void *)0,1)<0) error("shmat"); // son allocate data into his address scope
    				    
                    if (data.m%2 != 0) data.m*=2;  // modify variable
    		else data.m-=1;	
    	    }
    
    }  // qui termina il ciclo for
    
    if(pid>0) {
        printf("valore: %d\n", data.m);
    }

    ultimo dubbio che ho e poi non ti disturbo più

    la consegna dell'esercizio mi dice di generare n figli (n = argv[1]). io ho fatto così:

    codice:
    for(int i=0;i<atoi(argv[1]);i++) {
        if((pid=fork())<0) error("fork");
    }
    però se avessi fatto così, cosa cambia?

    codice:
    pid=fork(); //fork iniziale
    
    for(int i=0;i<argv[1];i++) {
        if(pid > 0) 
            pid = fork(); //faccio la fork solo sul padre
    }
    grazie davvero, mi salvi un'esame

    ciao,

    L.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.