From 47aaae2c42d554963fb811b68fdf28c9743598e8 Mon Sep 17 00:00:00 2001 From: Stefan Zabka Date: Wed, 10 Jun 2020 17:10:02 +0200 Subject: Starting threadpool --- 04_exercise/threadpool.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 04_exercise/threadpool.h (limited to '04_exercise/threadpool.h') diff --git a/04_exercise/threadpool.h b/04_exercise/threadpool.h new file mode 100644 index 0000000..6b758cd --- /dev/null +++ b/04_exercise/threadpool.h @@ -0,0 +1,116 @@ +#ifndef THREADPOOL_H_INCLUDED +#define THREADPOOL_H_INCLUDED + +#include + +/**@brief Funktionszeiger auf eine asynchron auszuführende Funktion. + * + * Der Parameter kann zur Übergabe von Argumenten und den Rückgabewerten + * der Funktion genutzt werden. + */ +typedef void (*ThreadTask_f)(void*); + +/**@brief Handle zum zukünftigen Rückgabewert eines asynchronen Funktionsrufes. + */ +typedef struct Future { + ThreadTask_f fn; ///<@brief Zeiger auf die auszuführende Funktion. + /* TODO: benötigte Attribute hinzufügen */ +} Future; + +/**@brief Initialisiert den globalen Thread-Pool. + * + * Diese Funktion legt \p size viele Worker-Threads an und initialisiert den + * restlichen Zustand des Thread-Pools. Danach werden keine weiteren Threads + * mehr durch den Thread-Pool angelegt. + * + * @param size Anzahl der Worker-Threads + */ +extern int tpInit(size_t size); + +/**@brief Beendet alle Worker-Threads im Thread-Pool kontrolliert und gibt + * sämtliche Systemressourcen des Thread-Pools frei. + * + * Bereits gestartete Futures können abgebrochen oder fertiggestellt werden. + */ +extern void tpRelease(void); + +/**@brief Startet eine nutzerdefinierte Future. + * + * Die Funktion initialisiert die übergebene Future und fügt sie zur Liste + * der abzuarbeitenden Tasks hinzu. Die Abarbeitungsreihenfolge ist + * unspezifiziert und die Abarbeitung startet sofort (eager). + * + * @param future partiell-initialisiertes Future-Objekt + * @note Der Rufer ist dafür verantwortlich, dass der Speicher nicht vor + * der Auswertung des asynchronen Funktionsrufes freigegeben wird. + */ +extern void tpAsync(Future *future); + +/**@brief Erwartet die Abarbeitung einer Future. + * + * Nachdem diese Funktion zurückgekommen ist, ist der asynchrone Funktionsruf + * garantiert abgeschlossen und der Zugriff auf die Future Data-Race-frei. + * Die Funktion gibt auch alle Systemressourcen des Thread-Pools frei. + * + * @param future asynchron gestartetes Future-Objekt + * @note Der Rufer kann danach den Speicher für die Future wieder freigeben. + */ +extern void tpAwait(Future *future); + +/**@brief Erzeugt Code für eine spezialisierte Schnittstelle einer Funktion. + * + * Die direkte Nutzung der minimalistischen Schnittstelle des Thread-Pools ist + * unkomfortabel und fehleranfällig, daher ist hier ein Makro definiert, + * mithilfe dessen eine spezifische Schnittstelle für asynchrone Funktionen + * erzeugt werden kann. + * + * Das Makro muss im Filescope expandiert werden und erzeugt folgende Elemente: + * 1. eine spezifische Datenstruktur für Argumente und Rückgabewerte der + * konkreten Funktion mit dem Namen `func_fut` + * 2. eine sogenannte thunk-Funktion mit dem Namen `funcThunk`, welche die + * Funktionsargumente aus dem generischen Argument entpackt, die konkrete + * Funktion ausführt und dann den Rückgabewert zurückschreibt + * 3. eine asynchrone Ruf-Funktion mit dem Namen `funcAsync`, welche ein + * Future-Objekt initialisiert und zurückgibt + * 4. eine synchrone Warte-Funktion mit dem Namen `funcAwait`, welche auf die + * Abarbeitung eines zuvor asynchron gerufenen Future-Objektes wartet und + * das Ergebnis zurückgibt + * + * Zusätzlich dazu wird die konkrete Funktion anfangs deklariert. + * Benutzung ist wie folgt möglich: + * @code + * // deklariert die Schnittstelle einer Funktion ´long fib(long)´ + * TASK(long, fib, long); + * @endcode + * + * @param TYPE Rückgabetyp der Funktion + * @param NAME Name der Funktion + * @param ARG Parametertyp der Funktion + */ +#define TASK(TYPE, NAME, ARG) \ + TYPE NAME(ARG); \ + \ + typedef struct { \ + Future fut; \ + ARG arg; \ + TYPE res; \ + } NAME ## _fut; \ + \ + static void NAME ## Thunk(void *args) { \ + NAME ## _fut *data = args; \ + data->res = NAME(data->arg); \ + } \ + static inline NAME ## _fut NAME ## Future(ARG arg) { \ + return (NAME ## _fut) { \ + .fut = { .fn = &NAME ## Thunk }, \ + .arg = arg \ + }; \ + } \ + static inline NAME ## _fut* NAME ## Async(NAME ## _fut *future) { \ + return tpAsync(&future->fut), future; \ + } \ + static inline TYPE NAME ## Await(NAME ## _fut *future) { \ + return tpAwait(&future->fut), future->res; \ + } + +#endif -- cgit v1.2.3-54-g00ecf