Sync / Semaphores und Signals werden verwendet um Zugriff auf geteilte Ressourcen zu koordinieren. Zudem können damit Threads aufeinander warten.
Syncs werden notwendig, wenn ein Thread auf einen anderen warten muss.
- z.B. wenn eine Resource im einten geöffnet ist, dann darf der andere diese erst öffnen, sobald der erste durch ist.
- Oder in einer kritischen Funktion, die IMMER ganz durchlaufen werden muss.
// Mit dem volatile keyword wird klargestellt,
// dass diese Resource von mehreren Threads verwendet wird.
volatile int iAmShared = 0;
Mutex - Mutual Exclusion
- Resourcen werden gegenseitig ausgeschlossen, ein Task blockiert den Eintritt für andere Tasks in die Crititcal Section
Probleme
- Runtime Kosten (locks dauern)
- Rekursion
- Kein Unlock (Bei early return)
- Deadlock
#include <sys/types.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
const int N = 100000000;
// shared value
volatile int value = 0;
pthread_mutex_t mutex;
void * count(void * arg)
{
int delta = *(int*) arg;
for (int i = 0; i < N; i++)
{
if (pthread_mutex_lock(&mutex) != 0)
{
perror("Mutex konnte nicht besetzt werden");
exit(EXIT_FAILURE);
}
// Gemeinsame Variable auslesen
int a = value;
// Modifiziern
a += delta;
// Variable wieder setzen
value = a;
// Mutex wieder freigeben
if (pthread_mutex_unlock(&mutex) != 0)
{
perror("Mutex konnte nicht freigegeben werden");
exit(EXIT_FAILURE);
}
}
return NULL;
}
int main (void)
{
if (pthread_mutex_init(&mutex, NULL) != 0)
{
perror("Mutex konnte nicht initialisiert werden");
exit(EXIT_FAILURE);
}
pthread_t th_inc;
pthread_t th_dec;
int inc = +1;
int dec = -1;
if (pthread_create(&th_inc, NULL, count, &inc) != 0)
{
perror("Thread konnte nicht erstellt werden");
exit(EXIT_FAILURE);
}
if (pthread_create(&th_dec, NULL, count, &dec) != 0)
{
perror("Thread konnte nicht erstellt werden");
exit(EXIT_FAILURE);
}
// noch auf threads waretn
if (pthread_join(th_inc, NULL) != 0)
{
perror("Thread konnte nicht beendet werden");
exit(EXIT_FAILURE);
}
if (pthread_join(th_dec, NULL) != 0)
{
perror("Thread konnte nicht beendet werden");
exit(EXIT_FAILURE);
}
}
gcc -pthread t10/critical_section.c
Semaphore
Tasks können über Semaphoren Synchronisationspunkte vereinbaren
Probleme
- Synchronisation kostet Zeit
- Wenn ein wait zu viel, bzwh. ein signal zu wenig
- Deadlocks, System kann komplett blockiert werden
// C program to demonstrate working of Semaphores
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mutex;
void* thread(void* arg)
{
//wait
sem_wait(&mutex);
printf("\nEntered..\n");
//critical section
sleep(4);
//signal
printf("\nJust Exiting...\n");
sem_post(&mutex);
}
int main()
{
// 1 -> Initial value
// unbedingt auf das achten
sem_init(&mutex, 0, 1);
pthread_t t1,t2;
pthread_create(&t1,NULL,thread,NULL);
sleep(2);
pthread_create(&t2,NULL,thread,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
sem_destroy(&mutex);
return 0;
}
gcc -pthread t10/semaphore.c