C Programm zu shared memory und semaphore



  • Hallo Community,

    Ich studiere momentan praktische Informatik an einer Fachhochschule und habe im Rahmen einer Pflichtabgabe folgende Aufgabenstellung bekommen:

    "Aufgabe 2 (Semaphoren und Shared Memory)

    Implementieren Sie folgendes Erzeuger-Verbraucher-Schema mit Hilfe von Shared Memory und Semaphoren.ein Veterprozess p1 legt Semaphoren und shared memory Segment an. Danach erzeugt er den Sohnprozess p2, der als Prozesskopie die Semaphoren-id und die Shared-mem-id kennt. Der Prozess p1 wird Daten in den gemeinsamen Speicher schreiben, die Prozess p2 dort herauslesen wird.

    Der Erzeugerprozess P2 hält ein Array gefüllt mit int-Daten, deren Anzahl sei durch eine

    #define N_DATA 2000000

    Direktive festgelegt. Die Daten werden von P1 zufällig erzeugt (siehe srand48 und lrand48)
    Der Verbraucherprozess P2 soll diese Daten erhalten, indem diese über einen von p1 und p2 genutzten gemeinesamen shared memory block übertragen werden. Im shared-memory Bereich finden weniger als N_DATA viele Zahlen Platz, etwa

    #define N_SHARED 2000

    Prozess p1 muss also die größere Anzahl von Daten in mehreren Durchläufen durch den kleineren Shared Puffer übertragen."

    Folgendes habe ich daraufhin gebastelt:

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/stat.h>
    #include<sys/sem.h>
    #include<sys/shm.h>
    
    #define KEY 		123458L
    #define LOCK 		0
    #define UNLOCK  	1
    #define PERM		0666	//Zugriffsrechte
    #define N_DATA  	2000000
    #define N_SHARED 	2000	//shared memory groesse
    
    static struct sembuf semaphore;
    static int semid, shid;
    int i;
    char *myPtr;
    
    static int init_semaphore (void) {
    
    	//existiert die semaphore schon?
    	semid = semget (KEY, 0, IPC_PRIVATE);
    
    	//existiert noch nicht, also anlegen
    	if (semid < 0) {
    
    		//alle Zugriffsrechter erlauben
    		umask (0);
    
    		//die eigentliche Erstellung
    		semid = semget (KEY, 1, IPC_CREAT | IPC_EXCL | PERM);
    
    		//Wenn jetzt noch nicht existent, dann gabe es einen Fehler
    		if (semid < 0 ) {
    			printf ("Fehler beim Anlegen der Semaphore...\n");
    			return -1;
    		}
    
    		printf ("(angelegt) Sem-ID: %d\n", semid);
    
    		//Sem mit 1 initialisieren, wenn die Funktion -1 returned gab es einen Fehler
    		if (semctl (semid, 0, SETVAL, (int) 1) == -1)
    			return -1;
    	}
    	//Wenn die Funktion bis hier her kommt war sie erfolgreich
    	return 1;
    }
    
    static int semaphore_operation (int op) {
    
    	semaphore.sem_op = op;
    	semaphore.sem_flg = SEM_UNDO;
    
    	//Wenn das nicht funktioniert gab es einen Fehler
    	if (semop (semid, &semaphore, 1) == -1) {
    		perror (" semop ");
    		return -1;
    	}
    
    	return 1;
    }
    
    static int init_shared_mem (void) {
    
    	//shared Memory erzeugen an der Stelle KEY, mit groesse N_SHARED
    	shid = shmget (KEY, N_SHARED, IPC_CREAT | PERM);
    
    	//Wenn etwas schief gelaufen ist wird hier abgebrochen
    	if (shid < 0 ) {
    		perror ("Fehler beim erstellen der Shared Memory ... \n");
    		return -1;
    	} else {
    
    		//Speicher holen (shared memory attach)
    		myPtr = shmat (shid,(void *) 0, 0);
    
    		//Wenn etwas schief gelaufen ist
    //		if (myPtr == (char *) -1) {
    //			perror ("Fehler beim attachen der shared Memory ... \n");
    //			return -1;
    //		}
    	}
    
    	//Wenn das Programm bis hier her kommt war es erfolgreich
    	return 1;
    }
    
    int main (int argc, const char **argv[]) {
    
    	int i_sem_ret, i_shm_ret, copied, child_index, child_durchlaeufe, parent_durchlaeufe, parent_index, sec_parent_index, sem_op_ret;
    	int random_int_array [N_DATA];
    	pid_t forkPid;
    
    	//shared memory und semaphore initialisieren;
    	i_shm_ret = init_shared_mem();
    	i_sem_ret = init_semaphore();
    
    	if (i_shm_ret < 0)
    		return EXIT_FAILURE;
    
    	if (i_sem_ret < 0)
    		return EXIT_FAILURE;
    	//-----------------------------------------//
    
    	//int array mit zufallswerten fuellen
    	for (i=0; i<N_DATA ; i++)
    		random_int_array [i] = lrand48();
    	//-----------------------------------------//
    
    	//den ersten teil des int arrays uebertragen in die shared memory
    	myPtr = shmat (shid, 0, 0);
    
    	//ist was schief gelaufen?
    //	if (myPtr = (char *) -1){
    //		perror ("Fehler beim attachen der shared Memory...\n");
    //		return -1;
    //	} else /*alles hat geklappt*/ {
    		for (i=0 ; i<N_SHARED ; i++) {
    //			printf ("beim befuellen");
    			myPtr[i] = random_int_array[i];
    		}
    //	}
    
    	//---------------------------------------------------------------//
    
    	//forking
    	forkPid = fork ();
    
    	//hier ist, was im kindprozesss zu tun ist
    	if (forkPid == 0) {
    		for (child_durchlaeufe = 0; child_durchlaeufe < 1000 ; child_durchlaeufe) {
    			printf("forkpid =0\n");
    			//Semaphore schliessen, jetzt wird hier darauf zugegriffen
    			sem_op_ret = semaphore_operation (LOCK);
    
    			printf("sem_op_re %u", sem_op_ret);
    
    			if (sem_op_ret < 0) {
    				perror ("Semaphore lock hat nicht geklappt ... \n");
    				return -1;
    			}
    
    			for (child_index = 0 ; child_index < N_SHARED ; child_index++) {
    				printf ("shared memory an Stelle %u hat den Wert %d", child_index, myPtr [child_index]);
    			}
    
    			//Semaphore wieder oeffnen fuer alle prozesse
    			sem_op_ret = semaphore_operation (UNLOCK);
    
    			if (sem_op_ret < 0) {
    				perror ("Semaphore unlock hat nicht funktioniert ... \n");
    				return -1;
    			}
    
    			//warten, bis was anderes passiert ist
    			wait(NULL);
    		}
    	}
    
    	//hier ist, was im elternprozess zu tun ist
    	if (forkPid > 0){
    		for (parent_durchlaeufe = 0; parent_durchlaeufe <1000 ; parent_durchlaeufe++) {
    
    			//solange, bis alles aus dem random array einmal in dem shared memory gestanden hat
    			for (parent_index =0; (N_DATA/N_SHARED) -1 ; parent_index ++) {
    
    				//fuellen
    				for (sec_parent_index = 0 ; sec_parent_index < N_SHARED ; sec_parent_index ++) {
    
    					myPtr[sec_parent_index] = random_int_array[sec_parent_index];
    				}
    			}
    		}
    	}
    
    }
    

    zum einen läuft er momentan in einer Endlosschleife, die ich nicht mehr finde, zum anderen habe ich schon alles mögliche versucht, aber irgendetwas funktioniert nicht (wahrscheinlich das shmat).

    Wenn mir jemand helfen würde (und im optimalfall den fehler einfach beheben), dann wäre ich sehr dankbar 🙂

    MfG

    Do Re



  • DoRe schrieb:

    Hallo Community,
    Ich studiere momentan praktische Informatik

    klingt wie theoretisches Schwimmen. SCNR.



  • Welche Warnungen bekommst Du? Keine? Dann stell Warnungen in Deinem Compiler an, z.B. gcc -std=gnuc11 -Wall -pedantic ... .



  • Wegen der Endlosschleife solltest du dir Zeile 135 und 169 nochmal genauer ansehen. Was machen diese Schleifen und wann brechen Sie ab und durch welchen Code wird die Abbruchbedingung erreicht?

    Und dann solltest du dir evtl. nochmal Gedanken darüber machen, ob dein Ansatz mit der Semaphore ausreichend ist, um die Aufgabe zu lösen.

    Zum einen nutzt du die Semaphore nur im Verbraucherprozess was sicherlich schon mal falsch ist, da der Erzeugerprozess ja auch nicht auf den Speicher zugreifen sollte, wenn der Verbraucherprozess grade Daten rauskopiert. Zum anderen ist meines Wissens nach nicht garantiert, dass die Prozesse schön abwechselnd an die Reihe kommen. Was wird also passieren, wenn der Erzeugerprozess oder der Verbraucherprozess zweimal hintereinander an die Reihe kommt?

    Als letzte Anmerkung von mir solltest du dir noch einen anderen Kommentarstil angewöhnen. Kommentiere nicht was du machst, sondern warum du es machst. Was du machst steht ja eh schon im Code. Bspw. der folgende Kommentar ist ziemlich überflüssig:

    //shared Memory erzeugen an der Stelle KEY, mit groesse N_SHARED
    shid = shmget (KEY, N_SHARED, IPC_CREAT | PERM);
    

Anmelden zum Antworten