/****************************************/
/*                                      */
/*  Prof. Dr. Carsten Vogt              */
/*  Fachhochschule Koeln                */ 
/*  Fakultaet 07, Nachrichtentechnik    */
/*  http://www.nt.fh-koeln.de/vogt      */
/*                                      */
/*  Linux-C-Schnittstelle mit pthreads: */
/*  pthread_create(), pthread_exit()    */
/*                                      */
/****************************************/

// Unter Linux zu uebersetzen mit 'gcc -pthread ...' oder 'cc -pthread ...'

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

// globale Variable, die für alle Threads zugreifbar ist

int wertspeicher = 0;

// Funktion, die von einem Thread ausgeführt werden soll

void *ausgabe(void *p) {
 printf("Hier ist ein Thread\n");
 printf("Mein Funktionsparameter: %ld\n", *(long *)p);
 printf("Meine PID: %d\n",getpid());
 wertspeicher++;  // erhöht die gemeinsame globale Variable
 printf("Wertspeicher: %d\n\n",wertspeicher);
 pthread_exit(NULL);  // beendet den Thread
}

// Hauptprogramm

int main(int argc, char *argv[]) {

 pthread_t th1, th2;   // Nummern der neu erzeugten Threads
 long param1, param2;  // Parameter zur Übergabe an die Threads
 int err;              // Fehlercode von pthread_create()

 printf("PID des Hauptprogramms: %d\n",getpid());
 printf("Wertspeicher: %d\n\n",wertspeicher);

 // Erzeugung eines Threads
 printf("Erzeuge ersten Thread\n");
 param1 = 1111;
 err = pthread_create(&th1, NULL, ausgabe, &param1);
    // 1. Parameter: Rückgabewert = Nummer des neuen Threads
    // 2. Parameter: Attribute (hier: Standardattribute)
    // 3. Parameter: Funktion, die der Thread ausführen soll
    // 4. Parameter: Parameter für die Funktion
 if (err!=0) { printf("Fehler\n"); exit(-1); }
 printf("Thread-Nr. %lu\n\n",th1);

 // Erzeugung eines zweiten Threads
 printf("Erzeuge zweiten Thread\n");
 param2 = 2222;
 err = pthread_create(&th2, NULL, ausgabe, &param2);
 if (err!=0) { printf("Fehler\n"); exit(-1); }
 printf("Thread-Nr. %lu\n\n",th2);
 
 sleep(1);
  // Dieses sleep gibt den Threads die Chance, ihre Ausgaben zu machen, bevor der gesamte Prozess mit dem Ende von
  // main() terminiert (und damit auch die soeben erzeugten Threads). Ganz sauber ist diese Art der Programmierung
  // aber nicht, denn unter sehr ungünstigen Umständen kann es vorkommen, dass die Threads länger als eine Sekunde
  // benötigen.
  // Alternativ kann man am Ende von main() pthread_exit(NULL) aufrufen. Damit würde nur der Hautprpogramm-Thread
  // beendet; die anderen Threads laufen also weiter. Allerdings müsste man dann die beiden Variablen param1
  // und param2 global deklarieren, damit diese auch nach Ende des Hauptprogramm-Threads noch existieren.
  // Eine zweite Möglichkeit wäre, das Ende der beiden Threads mit pthread_join abzuwarten.
}

