05.11.2013 Aufrufe

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

Zahn - Unix-Netzwerkprogramminerung mit Threads, Sockets und SSL

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

112 3 Programmieren <strong>mit</strong> POSIX-<strong>Threads</strong><br />

38–41<br />

Anders als Beispiel 3.1 fängt Beispiel 3.2 zum Ende der main()-Funktion<br />

nicht alle zuvor gestarteten <strong>Threads</strong> <strong>mit</strong> pthread_join() ein, sondern ruft<br />

nach einer kurzen Pause sofort die exit()-Funktion auf.<br />

Ein Testlauf des Programms bringt, je nach Standpunkt, erstaunliches zutage:<br />

$ ./pthreads-exit1<br />

Programm läuft.<br />

Thread gestartet, Programm läuft weiter.<br />

Thread Nr. 4 läuft.<br />

Thread Nr. 4 läuft.<br />

Thread Nr. 4 läuft.<br />

Hauptthread beendet sich.<br />

Als erstes sticht ins Auge, daß zwar drei <strong>Threads</strong> gestartet wurden, daß die<br />

zweite Kontrollausgabe der <strong>Threads</strong> jedoch fehlt <strong>und</strong> die <strong>Threads</strong> offensichtlich<br />

nicht ordentlich beendet wurden. Die Erklärung ist einfach, denn der<br />

main()-Thread wird nach dem Starten der neuen <strong>Threads</strong> <strong>und</strong> seiner Kontrollausgabe<br />

in Zeile 42 einfach <strong>mit</strong> exit() verlassen. In der Folge werden<br />

alle noch laufenden <strong>Threads</strong> vom System unverzüglich abgebrochen <strong>und</strong> der<br />

Prozeß beendet sich.<br />

Je nach Scheduling-Strategie <strong>und</strong> Systemlast hätte der Ablauf aber auch ganz<br />

anders sein können. Beispiel: Nach dem pthread_create() (Zeile 30) erhalten<br />

zunächst die neuen <strong>Threads</strong> CPU-Zeit zugewiesen, der Hauptthread verweilt<br />

im Ready-Zustand. Die <strong>Threads</strong> laufen jeweils bis zum sleep() (Zeile 13)<br />

<strong>und</strong> gehen dann in den Blocked-Zustand über. Anschließend entzieht das Betriebssystem<br />

dem kompletten Prozeß die CPU. Erst nach 30 Sek<strong>und</strong>en kommt<br />

der Prozeß das nächste Mal zum Zug. Die schlafenden <strong>Threads</strong> werden nacheinander<br />

geweckt, die Wartezeit von sleep() ist schließlich abgelaufen, <strong>und</strong><br />

beenden sich ordnungsgemäß. Erst danach erhält der main()-Thread wieder<br />

CPU-Zeit, verläßt die Schleife, legt sich für fünf Sek<strong>und</strong>en schlafen um dann<br />

die exit()-Funktion aufzurufen <strong>und</strong> den Prozeß zu beenden.<br />

Als zweites fällt auf, daß zwar die geforderten drei Pthreads gestartet wurden,<br />

daß aber offensichtlich alle drei <strong>Threads</strong> die selbe laufende Nummer erhalten<br />

haben. Ein zweiter Blick auf den Quellcode läßt uns die Ursache schnell lokalisieren:<br />

In Zeile 30 wird den neuen <strong>Threads</strong> über pthread_create() jeweils<br />

eine Referenz auf die Variable i übergeben. Da aber keine Synchronisation<br />

zwischen der Rückkehr aus dem Aufruf von pthread_create() <strong>und</strong><br />

dem tatsächlichen Start des <strong>Threads</strong>, also dem Übergang vom Ready- in den<br />

Running-Zustand, besteht, hat der Hauptthread den Zähler in der Regel bereits<br />

weiter inkrementiert, bevor der neue Thread den Zeiger erstmals dereferenziert.<br />

Beim Testlauf hatte i also schon den Wert 4 angenommen, bevor<br />

der erste Thread auf die Variable zugegriffen hat. Je nach Scheduling-Strategie<br />

des Systems hätte die Ausgabe aber auch korrekt erscheinen können, obwohl<br />

das Verfahren definitiv nicht richtig implementiert wurde.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!