Speicherzugriffsfehler bei Semaphoren



  • Der fehler tritt beim ausführen auf, in der funktion "philosophen" habe ich zum testen die Zeilen mit printf eingebaut, es gibt auch eine bis vier ausgaben, dann wird das programm abgebrochen und es steht dort:

    "make *** [runk] Speicherzugriffsfehler"

    runk, ist der befehl im makefile skript zur ausführung des programms.



  • Das int i bei void * philosoph(int i) beißt sich irgendwie mit dem &i bei pthread_create(&tid, NULL, (void *)philosoph, &i)

    Das Argument von philosoph sollte schon ein void * sein, das du dann in philosoph durch casten und dereferenzieren zu einem int bekommst.



  • das ja mist, wie soll ich die for schleife denn mit einem void laufen lassen?

    ich hätte auch noch ne frage zu den threads, für das problem der speisenden philosophen soll jeder philosoph in einem thread ausgeführt werden. versteh ich es richtig das ich demnach 5x pthread_create() aufrufe, dann eine schleife mache in der 5x pthread_join steht? dann sollten ja alle threads laufen und durch die semaphore warten oder passieren...?



  • DaPole schrieb:

    das ja mist, wie soll ich die for schleife denn mit einem void laufen lassen?

    Wieso for-schleife mit void?

    Die for-Schleife ist doch in Ordnung.

    pthread_create erwrtet als 4. Argument ein void-Zeiger auf eine Datenstrucktur, die an die Funktion (der 3. Parameter) weitergegeben wird.
    Ist in Ordnung bei dir, du übergibst die Adresse von i.

    Deine philosoph-Funktion bekommt als Argument eben diesen void-Zeiger mitgegeben. In deinem Fall ist es die Adresse von i (so steht es beim pthread_create-Aufruf).

    Also musst du in philosph aus dem void * ein int kriegen.
    Na gut:

    void * philosoph(void *v)
    { int i;
    ...
      i = *(int *)v; // casten und dereferenzieren
    dein Rest hier
    }
    


  • Hi, das programm läuft jetzt einwandfrei, danke für die hilfe.

    nun hab ich nur noch eine unsicherheit. im moment läuft das programm ohne ein ende zu erreichen. ich würde gerne das programm mit drücken der ENTER taste beenden, nun hab ich mir üerlegt das man das mit einer globalen variable realisieren kann. nun die frage wo sollte ich das in diesem Programm einbauen? in der Main oder bei den Philosophen?

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    //Anzahl der Philosophen
    #define PHILOSOPHEN 5
    
    #define DENKEN 0
    #define HUNGRIG 1
    #define ESSEN 2
    #define LINKS (phil_nummer+4)%PHILOSOPHEN
    #define RECHTS (phil_nummer+1)%PHILOSOPHEN
    
    //Definition der globalen Semaphoren
    sem_t forks[PHILOSOPHEN];
    
    sem_t diener;
    
    void * philosoph(void *num);
    void nehme_gabel(int);
    void lege_gabel(int);
    void test(int);
    
    int state[PHILOSOPHEN];
    int phil_nummer[PHILOSOPHEN]={0,1,2,3,4};
    char running;	
    
    //Semaphor wird nur zwischen Threads getauscht
    #define INTERN_THREAD 0
    
    void * philosoph(void *num)
    {
    	while(1)
    	{
    		int i = *(int *) num; 
    		nehme_gabel(i);
    		lege_gabel(i);
    	}
    }
    
    void nehme_gabel(int phil_nummer)
    {
    	sem_wait(&diener);
    	state[phil_nummer] = HUNGRIG;
    	printf("Phil %d ist Hungrig\n", phil_nummer+1);
    	test(phil_nummer);
    	sem_post(&diener);
    	sem_wait(&forks[phil_nummer]);
    }
    
    void lege_gabel(int phil_nummer)
    {
    	sem_wait(&diener);
    	state[phil_nummer] = DENKEN;
    	printf("Phil %d denkt\n",phil_nummer+1);
    	sleep(1);
    	test(LINKS);
    	test(RECHTS);
    	sem_post(&diener);
    }
    
    void test(int phil_nummer) 
    {
    	if(state[phil_nummer]==HUNGRIG&&state[LINKS] != ESSEN &&state[RECHTS] != ESSEN)
    	{
    		state[phil_nummer] = ESSEN;
    		sleep(2);
    		sem_post(&forks[phil_nummer]);
    	}
    }
    
    int main(int argc, char *argv[])
    {
    	int i;
    	pthread_t tid[PHILOSOPHEN];	
    
    	for(i=0; i<PHILOSOPHEN; i++) {
    		if (sem_init(&forks[i], INTERN_THREAD, 0) < 0) {
    			perror("sem_init_fork");
    			return(1);
    		}
    	}
    
    	if (sem_init(&diener, INTERN_THREAD, 1) < 0) {
    		perror("sem_init_diener");
    		return(1);
    	}
    
    	for (i=0; i<PHILOSOPHEN; i++) {
    		if(pthread_create(&tid[i], NULL, (void *)philosoph, &phil_nummer[i]) == -1) {
    			perror("create");
    			return(1);
    		} 		
    	}
    
    	for(i=0; i<PHILOSOPHEN; i++) {
    		if(pthread_join(tid[i],NULL) == -1) {
    			perror("join");
    			return(1);
    		}
    	}
    
    getchar();
    return (0);
    }
    


  • Wo willst du das denn in der main machen?
    Das pthread_join blockiert solange, bis der thread beendet wurde.

    Und bei #define LINKS (phil_nummer+4)%PHILOSOPHEN solltest du die 4 durch (PHILOSOPHEN-1) ersetzen.
    Das int phil_nummer[PHILOSOPHEN]={0,1,2,3,4}; ist besser in eine Schleife aufgehoben, bzw. phil_nummer[i] = i direkt vor pthread_create.
    Dann kannst du auch mal PHILOSOPHEN mit einem anderen Wert definieren.



  • danke, das mit der veränderten anzahl an philosophen ist zwar nicht nötig, aber schadet nicht.

    bezüglich der main hast du recht, denkfehler von mir.
    also bei dem philosophen, das problem ist das bei der benutzung von getchar() diese auf eine eingabe wartet, ich will aber das die philosophen solange speisen bis ich enter drücke.



  • Das musst du dann wohl in Zeile 96 machen.



  • joa soweit bin ich auch, bräuchste nur ein tipp wie ich da herangehen soll. sobald ich nen getchar() reinschreibe muss ich vor jedem durchlauf enter drücken soweit ich mich nicht irre.

    ich will aber das die philosophen solange speisen bis ich ENTER drücker. sobald das geschieht kommt ein textausgabe welcher philosoph wie oft gegessen hat.



  • 😕
    Zeile 96 ist die leere Zeile zwischen deiner pthread_create-Schleife und der pthread_join-Schleife.

    perror("create");
                return(1);
            }        
        }
    // Diese Zeile hier ist gemeint
        for(i=0; i<PHILOSOPHEN; i++) { // diese nicht
            if(pthread_join(tid[i],NULL) == -1) {
    

    Da wartest du auf den Tastendruck.
    Dann teilst du den Threads mit, dass sie sich beenden sollen (wie auch immer)

    Und dann sammelst du sie wieder mit pthread_join ein.



  • das du die leere zeile meinst war mir beuwsst, sory wenn das nicht rüberkam.

    mein programm sieht jetzt folgendermaßen aus(siehe unten):

    Wenn ich nun zweimla auf Enter drüpcke beendet er sich nach 10sek (wegen sleep(10)) allerdings essen die philosophen bis zum ende, und das letzte getchar() wird ignoriert genau wie die printf vorher (es sei denn es geht so schnell von statten das man es nicht wahrnehmen kann.

    Nun hab ich versucht das mit pthread_exit() hinzubekommen, allerdings bringt das auch nicht den erhofften erfolg...

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    //Anzahl der Philosophen
    #define PHILOSOPHEN 5
    
    #define DENKEN 0
    #define HUNGRIG 1
    #define ESSEN 2
    #define LINKS (phil_nummer+(PHILOSOPHEN-1))%PHILOSOPHEN
    #define RECHTS (phil_nummer+1)%PHILOSOPHEN
    
    //Definition der globalen Semaphoren
    sem_t forks[PHILOSOPHEN];
    
    sem_t diener;
    
    void * philosoph(void *num);
    void nehme_gabel(int);
    void lege_gabel(int);
    void test(int);
    
    int phil_nummer[PHILOSOPHEN];
    int state[PHILOSOPHEN];
    int anzahl_essen[5] = {0,0,0,0,0};	
    
    int running;
    
    //Semaphor wird nur zwischen Threads getauscht
    #define INTERN_THREAD 0
    
    void * philosoph(void *num)
    {
    	while(1)
    	{
    		int i = *(int *) num; 
    		nehme_gabel(i);
    		lege_gabel(i);
    	}
    }
    
    void nehme_gabel(int phil_nummer)
    {
    	sem_wait(&diener);
    	state[phil_nummer] = HUNGRIG;
    	printf("Phil %d ist Hungrig\n", phil_nummer+1);
    	test(phil_nummer);
    	sem_post(&diener);
    	sem_wait(&forks[phil_nummer]);
    }
    
    void lege_gabel(int phil_nummer)
    {
    	sem_wait(&diener);
    	state[phil_nummer] = DENKEN;
    	printf("Phil %d denkt\n",phil_nummer+1);
    	usleep(150);
    	test(LINKS);
    	test(RECHTS);
    	sem_post(&diener);
    }
    
    void test(int phil_nummer) 
    {
    	if(state[phil_nummer]==HUNGRIG&&state[LINKS] != ESSEN &&state[RECHTS] != ESSEN)
    	{
    		state[phil_nummer] = ESSEN;
    		printf("Phil %d isst\n",phil_nummer+1);
    		anzahl_essen[phil_nummer]++;
    
    		usleep(10);
    		sem_post(&forks[phil_nummer]);
    	}
    }
    
    int main(int argc, char *argv[])
    {
    	int i;
    	pthread_t tid[PHILOSOPHEN];	
    
    		for(i=0; i<PHILOSOPHEN; i++) {
    		if (sem_init(&forks[i], INTERN_THREAD, 0) < 0) {
    			perror("sem_init_fork");
    			return(1);
    		}
    	}
    
    	if (sem_init(&diener, INTERN_THREAD, 1) < 0) {
    		perror("sem_init_diener");
    		return(1);
    	}
    
    	for(int i=0; i<PHILOSOPHEN; i++) 
    		phil_nummer[i] = i;
    
    	for (i=0; i<PHILOSOPHEN; i++) {
    		if(pthread_create(&tid[i], NULL, (void *)philosoph, &phil_nummer[i]) == -1) {
    			perror("create");
    			return(1);
    		} 		
    	}
    
            while(getchar() != '\n') {
    	for(i=0; i<PHILOSOPHEN; i++) {
    		if(pthread_join(tid[i],NULL) == -1) {
    			perror("join");
    			return(1);
    		}
                } 
    	}
    
    	sleep(10);
    	printf("phil1 = %d\n"
    			 "phil2 = %d\n"
    			 "phil3 = %d\n"
    			 "phil4 = %d\n"
    			 "phil5 = %d\n",anzahl_essen[0], anzahl_essen[1], anzahl_essen[2],
    								anzahl_essen[3], anzahl_essen[4]); 
    getchar();
    return (0);
    }
    


  • So Problem gelöst.

    in der Zeile ie du vorgeschlagen hast steht jetzt folgender Text:

    [cpp]if(getchar() == '\n')
    {
    for(int i=0; i<PHILOSOPHEN; i++)
    pthread_cancel(tid[i]);
    }

    und alles läuft so wie es soll.
    ich danke dir für deine zahlreichen und schnellen antworten, es ist immer wieder gut wenn man beim programmieren sich nicht stundenlang allein mit seinem problkem beschäftigt, man bekommt so ein schönen tunnelblick und macht immer und immer wieder das gleiche 😃

    schönen Tag noch



  • Warum denn das while um das join?
    Ein Tastendruck und dann soll es weitergehen.

    Wo beendest du denn die philosophen?
    Das pthread_join wartet nur darauf das sich die beendeten Threadss melden.

    Hast du das so probiert?

    int running = 1;
    ...
    void * philosoph(void *num)
    {
        int i = *(int *) num;
        while(running)
        {
            nehme_gabel(i);
            lege_gabel(i);
        }
        pthread_exit()
    }
    
    int main(...
    {
    ...
      while(getchar() != '\n') ; // (war) Zeile 96 Achtung Leerschleife. Hier wird auf \n gewartet.
      running = 0;
    
      join-Gedöns
    

Anmelden zum Antworten