4 Philosophen Problem mit Semaphoren
-
Hy.
Ich hatte die Aufgabe das 4-Philosophen Problem zu lösen und habe dazu ein kleines Programm geschrieben:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <pthread.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #define LOOP_SIZE 10 #define LOOP_END 100 #define KEYSHM 600 #define KEYSEM1 22 int semid; // global für alle threads /****************************************************************************** * pthread_sleep takes an integer number of seconds to pause the current thread * We provide this function because one does not exist in the standard pthreads * library. We simply use a function that has a timeout. *****************************************************************************/ int pthread_sleep (int seconds) { pthread_mutex_t mutex; pthread_cond_t conditionvar; struct timespec timetoexpire; if (pthread_mutex_init (&mutex, NULL)) return -1; if (pthread_cond_init (&conditionvar, NULL)) return -1; timetoexpire.tv_sec = (unsigned int) time (NULL) + seconds; timetoexpire.tv_nsec = 0; return pthread_cond_timedwait (&conditionvar, &mutex, &timetoexpire); } void *Thread1 (void *s) { // Philosoph 1 struct sembuf poperation[2], voperation[2], woperation[2]; poperation[0].sem_op = -1; poperation[0].sem_num = 0; // Semaphore-Array poperation[0].sem_flg = 0; voperation[0].sem_op = 1; voperation[0].sem_num = 0; voperation[0].sem_flg = 0; woperation[0].sem_op = 0; // Zustzäliche Warte-Operation = 0 woperation[0].sem_num = 0; woperation[0].sem_flg = 0; poperation[1].sem_op = -1; poperation[1].sem_num = 1; poperation[1].sem_flg = 0; voperation[1].sem_op = 1; voperation[1].sem_num = 1; voperation[1].sem_flg = 0; woperation[1].sem_op = 0; woperation[1].sem_num = 1; woperation[1].sem_flg = 0; if ((semid = semget (KEYSEM1, 4, 0600|IPC_CREAT)) == -1) { perror ("1 semget: semget failed"); exit (1); } semctl (semid, 0, SETALL, 0); while (1) { printf ("A: moechte Essen ..\n"); semop (semid, woperation, 2); // warte auf Freigabe printf ("A: == isst ==\n"); semop (semid, voperation, 2); // belege pthread_sleep (1); semop (semid, poperation, 2); // gibt frei printf ("A: denkt ..\n"); pthread_sleep (1); } semctl (semid, 0, IPC_RMID, 0); } void *Thread2 (void *s) { // Philosoph 2 struct sembuf poperation[2], voperation[2], woperation[2]; poperation[0].sem_op = -1; poperation[0].sem_num = 1; poperation[0].sem_flg = 0; voperation[0].sem_op = 1; voperation[0].sem_num = 1; voperation[0].sem_flg = 0; woperation[0].sem_op = 0; woperation[0].sem_num = 1; woperation[0].sem_flg = 0; poperation[1].sem_op = -1; poperation[1].sem_num = 2; poperation[1].sem_flg = 0; voperation[1].sem_op = 1; voperation[1].sem_num = 2; voperation[1].sem_flg = 0; woperation[1].sem_op = 0; woperation[1].sem_num = 2; woperation[1].sem_flg = 0; while (semid == -1) // warte Anfangs usleep (100000); while (1) { printf ("B: moechte Essen ..\n"); semop (semid, woperation, 2); printf ("B: == isst ==\n"); semop (semid, voperation, 2); pthread_sleep (1); semop (semid, poperation, 2); printf ("B: denkt ..\n"); pthread_sleep (2); } } void *Thread3 (void *s) { // Philosoph 3 struct sembuf poperation[2], voperation[2], woperation[2]; poperation[0].sem_op = -1; poperation[0].sem_num = 2; poperation[0].sem_flg = 0; voperation[0].sem_op = 1; voperation[0].sem_num = 2; voperation[0].sem_flg = 0; woperation[0].sem_op = 0; woperation[0].sem_num = 2; woperation[0].sem_flg = 0; poperation[1].sem_op = -1; poperation[1].sem_num = 3; poperation[1].sem_flg = 0; voperation[1].sem_op = 1; voperation[1].sem_num = 3; voperation[1].sem_flg = 0; woperation[1].sem_op = 0; woperation[1].sem_num = 3; woperation[1].sem_flg = 0; while (semid == -1) // warte Anfangs usleep (100000); while (1) { printf ("C: moechte Essen ..\n"); semop (semid, woperation, 2); printf ("C: == isst ==\n"); semop (semid, voperation, 2); pthread_sleep (2); semop (semid, poperation, 2); printf ("C: denkt ..\n"); pthread_sleep (1); } } void *Thread4 (void *s) { // Philosoph 4 struct sembuf poperation[2], voperation[2], woperation[2]; poperation[0].sem_op = -1; poperation[0].sem_num = 0; poperation[0].sem_flg = 0; voperation[0].sem_op = 1; voperation[0].sem_num = 0; voperation[0].sem_flg = 0; woperation[0].sem_op = 0; woperation[0].sem_num = 0; woperation[0].sem_flg = 0; poperation[1].sem_op = -1; poperation[1].sem_num = 3; poperation[1].sem_flg = 0; voperation[1].sem_op = 1; voperation[1].sem_num = 3; voperation[1].sem_flg = 0; woperation[1].sem_op = 0; woperation[1].sem_num = 3; woperation[1].sem_flg = 0; while (semid == -1) // warte Anfangs usleep (100000); while (1) { printf ("D: moechte Essen ..\n"); semop (semid, woperation, 2); printf ("D: == isst ==\n"); semop (semid, voperation, 2); pthread_sleep (2); semop (semid, poperation, 2); printf ("D: denkt ..\n"); pthread_sleep (2); } } int main (void) { pthread_t tid1, tid2, tid3, tid4; pthread_create (&tid1, NULL, Thread1, (void *) NULL); // erzeuge Philosophen pthread_create (&tid2, NULL, Thread2, (void *) NULL); pthread_create (&tid3, NULL, Thread3, (void *) NULL); pthread_create (&tid4, NULL, Thread4, (void *) NULL); pthread_join (tid1, NULL); pthread_join (tid2, NULL); pthread_join (tid3, NULL); pthread_join (tid4, NULL); return 0; }
Wie man sehen kann, habe ich das ganze mit 4 einzelnen Threads realisiert. Um das ganze hinzubekommen, habe ich neben der p & v Operation noch eine dritte 'Wait for Zero' Operation eingeführt.
Mein Prof will mir das Programm aber nicht abnehmen, da er meint, es könnte dazu kommen, dass alle 4 somit gleichzeitig essen, wenn eine zu große Pause zw der P und W Operation liegt. Irgendwie ist mir das so halb klar geworden, aber ich weiß einfach nicht, wie ich meine zusätzliche W-Operation unbrauchbar machen kann.
Kann mir evtl. jemand kurz erklären, wie ich auf diese Verzichten kann und das im Code umsetze? Irgendwie ist mir wohl was noch nicht klar geworden. Ich hock jetzt schon ein Weilchen davor und glaube langsam den Wald vor Bäumen nicht mehr zu sehen
Ein bisschen Unterstützung wäre echt Super