UNIX-Schnittstelle ================== 2. Threads ========== |
next | back | 2017 - 1 |
Alle Beispiel-Quellen mittels SVN unter: https://svn.informatik.hu-berlin.de/svn/unix-2014/Threads 2.1. Vorbemerkungen =================== Was ist ein Thread? ------------------- Einzelner, sequentieller Steuerungsfluss in einem Programm. Die meisten klassischen Programme bestehen aus einem Thread (single thread). Neu: Multithread Unterstützung: Das Betriebssystem erlaubt, dass ein Programm mehrere Threads enthält (multithread process) Dabei wird kein vollständiger neuer UNIX-Prozess benutzt. Heap, Code, Static-Data werden von den Threads gemeinsam benutzt. Stack und Register besitzt jeder Thread für sich. |
next | back | 2017 - 2 |
Single Threaded Process +-----------------------------------------+ | Prozess | | +--------+ | | |Register| | | +--------+ | | +- - - - - - - - - - - - - - - - - - + | | | Memory | | | +------+ +-------+ | | | | Heap | | | | | | +------+ | | | | | |Static| | Stack | | | | +------+ | | | | | | Code | | | | | | +------+ +-------+ | | +- - - - - - - - - - - - - - - - - - + | +-----------------------------------------+ |
next | back | 2017 - 3 |
Mulithreaded Process +---------------------------------------------------+ | Prozess +----------+----------+----------+ | | | Thread 1 | Thread 2 | Thread 3 | | | |+--------+|+--------+|+--------+| | | ||Register|||Register|||Register|| | | |+--------+|+--------+|+--------+| | | +- - - - - -|- - - - - |- - - - - |- - - - - |-+ | | | Memory | | | | | | | +------+ |+--------+|+--------+|+--------+| | | | | Heap | || ||| ||| || | | | +------+ || ||| ||| || | | | |Static| || Stack ||| Stack ||| Stack || | | | +------+ || ||| ||| || | | | | Code | || ||| ||| || | | | +------+ |+--------+|+--------+|+--------+| | | | +----------+----------+----------+ | | | +- - - - - - - - - - - - - - - - - - - - - - -+ | +---------------------------------------------------+ |
next | back | 2017 - 4 |
Beispiel: void do_one_thing(int *); void do_another_thing(int *); void do_wrap_up(int, int); main() { do_one_thing(&r1); do_anaother_thing(&r2); /*parallel*/ do_wrap_up(r1,r2) } Herkömliche Realisierungsmöglichkeiten: Threads/Simple/simple.c - in einem Prozess Threads/Simple/simple_processes.c - in mehreren Prozessen |
next | back | 2017 - 5 |
Implementationen - etwas Geschichte ----------------------------------- DEC-UNIX (1993) DECthreads nicht offengelegt cma Bibliothek für Digital Proprietary Interface auf DECthread-Basis SOLARIS (1993) LW-Prozesse - Systemcalls, offengelegt Solaris Threads - ähnlich POSIX 1003.4a PTHREAD (POSIX 1003.4a) ab DEC-UNIX 4.0E ab Solaris 2.6: POSIX 1003.4a ab Linux 2.0 - libpthread bis kernel 2.4 - PTL (Emulation in mehreren Prozessen) ab Kern 2.6 - NPTL (PTL mittels LD_ASSUME_KERNEL=2.4.1) |
next | back | 2017 - 6 |
Allgemeine Architektur für Threadinterface ------------------------------------------- traditioneller Prozess Prozess mit Multithreads Proc 1 Proc 2 User {T} {T} {T} {T} {T} Bounded Thread | | | | | | +-+-+-+-+ | | | | | o o o o +------------+-+-+-------+ | Kernel * | +---+--+--+ | | | [x] [x] [x] {T} - Thread, o - Execution resource (LWP,DECThread), [x] - Prozessor |
next | back | 2017 - 7 |
Arbeitsmodelle mit Threads ------------------------- 1. Boss/Worker Modell Ein Thread (Boss) übernimmt die Steuerung und übergibt weiteren Threads (Worker) Teilaufgaben. Die Worker melden den Arbeitszustand an den Boss. Ableitung davon ist das Work Queue Model, bei dem der Boss die Aufgaben in einer Workqueue plaziert und die Worker die Aufträge entnehmen. 2. Work Crew Modell Mehrere Threads erledigen zusammen eine Aufgabe. Prozess +---------+----------+---------+ | | Thread 1 | | | +----------+ | | Setup | Thread 2 | Cleanup | | +----------+ | | | Thread 3 | | +---------+----------+---------+ |
next | back | 2017 - 8 |
3. Pipelining Modell Beim Pipelining Modell wird die Aufgabe in mehrere nacheinander auszuführende Teilaufgaben zerlegt. Für jede Teilaufgabe wird ein Thread bereitgestellt, der die Eingangswerte vom vorhergehenden Thread übernimmt und die Ergebnisse an den nachfolgenden Thread übergibt. Prozess +----------+----------+----------+ | Thread 1 | Thread 2 | Thread 3 | +----------+----------+----------+ 4. Kombination der Modelle 1.-3. Kombinationen der Modelle 1.-3. sind für komplizierte Aufgaben üblich. Der Programmierer hat dabei alle Freiheiten. |
next | back | 2017 - 9 |
Arbeiten mit Threads -------------------- 1. Programmkomplexität Die Benutzung von Treads ist genau zu überlegen und nur dort einzusetzen wo sinnvoll. Oft wird durch den Verzicht auf Threads ein Geschwindigkeitsvorteil erreicht. Auch Threads erzeugen einen Overhead. Die Lesbarkeit von Programmen kann aber durch Threads erhöht werden. 2. Syncronisationsprobleme Zwei Threads greifen auf die gleiche Variable zu. Code Locking (ein Lock-Punkt im Prozess) Data Locking (kritische Variable durch Mutex-Variable oder Semaphore geschützt), flexibler als Code Locking 3. Deadlocks Gegenseitiges warten von Threads eigene Deadlocks oder rekursive Deadlocks Sheduling Deadlocks durch Prioritätsinversion (Threads blockieren sich durch überzogene Prioritätsforderungen gegenseitig) 4. Benutzung von nicht reenteranter Software Threads benutzen gleichzeitig Bibliotheksroutinen, die nicht reenterant sind. 5. Faustregeln für die Benutzung von Locks - Keine Locks über I/O-Operationen - Keine Locks beim Ruf von nicht reenteranten Funktionen - Keine überzogenen Prozessoranforderungen während Locks - Benutzung von multiplen Locks nur in gleicher Art und Weise |
next | back | 2017 - 10 |
Thread-Operationen - eine Übersicht ------------------------------------ Präfix für verschiede Threadbibliotheken: SOLARIS-Pthread, Linux - pthread_ SOLARIS-Threads - thr_ 1.Starten von Threads pthread_create (SOLARIS, LINUX) thr_create thr_min_stack 2. Beenden von Threads pthread_exit (SOLARIS, LINUX) thr_exit 3. Abbrechen von Threads pthread_cancel (SOLARIS, LINUX) 4. Warten auf das Ende von Threads pthread_join (SOLARIS, LINUX) thr_join 5. Freigeben von Threads (nach Abbruch oder Beendigung) pthread_detach (SOLARIS, LINUX) |
next | back | 2017 - 11 |
6. Holen eigenen Thread-Ident pthread_self (SOLARIS, LINUX) thr_self 7. Manipulation der Priorität von Threads Zahl der gleichzeitig aktiven Threads (Näherungswert) thr_setconcurrency, thr_getconcurrency Setzen/Holen der Priorität eines Threads pthread_getschedparam pthread_setschedparam (SOLARIS, LINUX) thr_setprio thr_getprio Freigeben des eigenen Prozessors für ein Thread mit gleicher Priorität pthread_yield (Linux) thr_yield (Solaris) Anhalten und starten von Threads thr_suspend, thr_continue 8. Initialisierung Einmaliges Abarbeitung einer Initialisierungsroutine pthread_once |
next | back | 2017 - 12 |
9. Manipulation von Attributen für Threads Thread-Attribute-Objekte verwalten SOLARIS/LINUX: pthread_attr_init, pthread_attr_destroy Wert für Guardsize im Attributobjekt pthread_attr_getguardsize_np pthread_attr_getguardsize pthread_attr_setguardsize_np pthread_attr_setguardsize Art der Prioritätsvererbung im Attributeobjekt SOL/LINUX: pthread_attr_getinheritsched pthread_attr_setinheritsched Wert für Priorität im Attributeobjekt pthread_attr_getprio cma_attr_get_priority pthread_attr_setprio cma_attr_set_priority Art des Schedulingtypes im Attributeobjekt pthread_attr_getsched cma_attr_get_sched pthread_attr_setsched cma_attr_set_sched SOLARIS/LINUX: pthread_attr_getschedparam, pthread_attr_setschedparam, pthread_attr_getschedpolicy,pthread_attr_setschedpolicy, pthread_attr_getscope, pthread_attr_setscope Wert für Stackgrösse im Attribeobjekt SOL/LINUX: pthread_attr_getstacksize, pthread_attr_setstacksize pthread_attr_getstackaddr, pthread_attr_setstackaddr |
next | back | 2017 - 13 |
2.2. Thread Bibliotheksrufe (SOLARIS/LINUX/POSIX) ================================================= Include-File: thread.h (pthread.h für POSIX-Threads) typedef unsigned int thread_t; typedef unsigned int thread_key_t; size_t thr_min_stack(void); #define THR_MIN_STACK thr_min_stack() /* thread flags (one word bit mask) */ #define THR_BOUND 0x00000001 #define THR_NEW_LWP 0x00000002 #define THR_DETACHED 0x00000040 #define THR_SUSPENDED 0x00000080 #define THR_DAEMON 0x00000100 thread_t thr_self(); void thr_yield(void); ... Bemerkungen zur Compilierung: SOLARIS/LINUX: pthreads: cc [ flag ... ] file ... -lpthread [ library ... ] SOLARIS: thread: cc [ flag ... ] file ... -lthread [ library ... ] |
next | back | 2017 - 14 |
1.Starten von Threads int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void * arg); int thr_create( void *stack_base, size_t stack_size, void *(*start_routine)(void *), void *arg, long flags, thread_t *new_thread_ID); Starten eines neun Threads in dem aktuellen Prozess. Es wird mit der Abarbeitung der Routine start_routine begonnen. Es kann für die Routine ein Parameter arg angegeben werden. Der Stack kann spezifiziert werden, wenn keine Werte angegeben werden (NULL,0), werden Standardwerte genommen (aus Heap THR_MIN_STACK Bytes). Wenn der thr_create erfolgreich war und new_thread != NULL wird in *new_thread der Identifier des neuen Threads abgelegt. Default-Attribute: NULL (SOLARIS/LINUX) Flags: THR_SUSPENDED - neuer Thread gestoppt, gestartet mit thr_continue() THR_DETACHED - Thread wird nach thr_exit sofort gestrichen (Rückkehrwerte nicht nutzbar) THR_BOUND - Eigener LWP THR_NEW_LP - Zahle der LWP's im Pool um 1 erhöhen THR_DAEMON - Dämon-Thread, wird nach dem letzten thr_exit eines Nicht-Dämon-Thread automatisch beendet Ruckkehrwerte: 0 - OK EAGAIN - Systemlimits (LWP) erschöpft ENOMEM - kein Speicher EINVAL - unzulässige Stackwerte |
next | back | 2017 - 15 |
2. Beenden von Threads void pthread_exit(void *value_ptr); void thr_exit(void *status); Beenden des aktuellen Threads. Hat der Thread den Status DETACHED, werden alle thread-spezifischen Objekte einschliesslich des Exit- Status ( value_ptr ) gelöscht. Andernfalls werden der Thread-ID und der Exit-Status gespeichert bis ein anderer Thread sie mit thr_join() abfordert. Rückkehrwert: keiner 3. Warten auf das Ende von Threads int pthread_join(pthread_t thread, void **value_ptr); int thr_join(thread_t wait_for, thread_t *departed, void **status); thr_join blockiert den aktuelle Thread bis der spezifizierte Thread ( wait_for ) beendet wird. Der Thread muss im aktuellen Prozess sein und nicht den Status DETACHED haben. Wenn wait_for den Wert (thread_t)0 hat, wartet thr_join auf das Ende eines beliebigen nicht DETACHED Thread des aktuellen Prozesses. Wenn departed != NULL ist, enthält *departed nach erfolgreicher Abarbeitung von thr_join den ID des beendeten Threads. **value_ptr enhält den Exit-Status des beendeten Threads, wenn value_ptr!=NULL ist. Rückkehrwerte: 0 - Ok ESRCH - ungültiger Parameter wait_for EDEADLK - wait_for spezifiziert den aktuellen Thread (Deadlock) |
next | back | 2017 - 16 |
Einfaches Beispiel mit Threads ------------------------------ Threads/Simple/simple_threads.c |
next | back | 2017 - 17 |
4. Holen der eigenen Thread-Ident pthread_t pthread_self(void); thread_t thr_self(void); Holen des eigenen Thread-ID. Rückkehrwert: eigener Thread-ID 5. Initialisierung von Threads int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)); Hiermit können sich mehrer Threads so synchronisieren, dass eine Funktion init_routine nur einmal abgearbeitet wird. Die Synchroni- sation erfolgt über eine Datenstruktur, die durch once_control adressiert wird. Rückerwert: immer 0 Beispiel -------- Einmalig Initialisierung Threads/Simple_once/once.c |
next | back | 2017 - 18 |
6. Manipulation der Priorität von Threads Zahl der gleichzeitig aktiven Threads (Näherungswert) int thr_getconcurrency(void) int thr_setconcurrency(int new_level) thr_getconcurrency ermittelt einen Näherungswert für die Zahl der gleichzeitig aktiven Threads (LWP's). Das System bestimmt selbst wieviele LWP's für eine bestimmte Anzahl von ungebundenen Threads notwendig sind. Mit thr_setconcurrency kann der Program- mierer die Zahl der LWP's ändern. Der übergebene Wert new_level dient dem System als Hinweis. Rückkehrwert: thr_getconcurrency - Wert thr_setconcurrency: 0 - Ok EAGAIN - Systemressourcen überschritten EINVAL - negativer Wert |
next | back | 2017 - 19 |
Setzen/Holen der Priorität eines Threads int thr_getprio(thread_t target_thread, int *priority); int thr_setprio(thread_t target_thread, int priority); SOLARIS/LINUX: int pthread_getschedparam(pthread_t target_thread, int *policy, struct sched_param *param); int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param); struct sched_param { int __sched_priority; }; pthread_getschedparam, thr_getprio speichert die aktuelle Priorität des Threads thread nach param.__sched_priority . pthread_setschedparam, thr_setprio setzt die aktuelle Priorität des Threads thread auf den Wert param.__sched_priority . Rückkehrwert: 0 - OK ESRCH - Thread exitiert nicht im aktuellen Prozess EINVEL - unzulässiger Prioritätswert |
next | back | 2017 - 20 |
Freigeben des eigenen Prozessors void pthread_yield(); void thr_yield(); thr_yield übergibt die Steuerung an einen anderen Thread mit gleicher oder höherer Priorität. Anhalten und starten von Threads int thr_suspend(thread_t target_thread); int thr_continue(thread_t target_thread); thr_suspend stoppt sofort die Arbeit des durch target_thread spezifizierten Threads. thr_continue aktiviert den durch thr_suspend gestoppten. bzw. durch thr_create() noch nicht gestarteten Thread target_thread wieder. thr_suspend hat auf einen gestoppten Thread keine Wirkung. thr_continue hat auf einen arbeitenden Thread keine Wirkung. |
next | back | 2017 - 21 |
Beispiel Copy (mit SUN-Threads) ------------------------------- Nur für Solaris!!!!!! Kopieren von Standard-Eingabe nach Standard-Ausgabe Threads/My/copy.c Wirkung von fork Threads/Fork/fork.c - fork in einem Thread Threads/Fork/fork1.c - fork1 (Solaris) Threads/Fork/fork2.c - fork Threads/Fork/fork3.c - forkall (Solaris) Threads/Fork/vfork.c - vfork, unsicher |
back | 2017 - 22 |