120
Jürgen Wolf Linux-UNIX-Programmierung Das umfassende Handbuch

Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Jürgen Wolf

Linux-UNIX-ProgrammierungDas umfassende Handbuch

Page 2: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Auf einen Blick

1 Einführung ....................................................................................... 29

2 E/A-Funktionen ................................................................................ 43

3 Attribute von Dateien und Verzeichnissen ....................................... 115

4 Zugriff auf Systeminformationen ...................................................... 129

5 Devices – eine einfache Verbindung zur Hardware .......................... 149

6 System- und Benutzerdateien .......................................................... 169

7 Dämonen, Zombies und Prozesse .................................................... 187

8 Signale ............................................................................................. 255

9 IPC – Interprozesskommunikation ................................................... 275

10 Threads ............................................................................................ 349

11 Netzwerkprogrammierung ............................................................... 407

12 MySQL und PostgreSQL .................................................................. 519

13 Terminal E/A und Benutzerschnittstellen für die Konsole ................ 653

14 GTK+ ................................................................................................ 715

15 Übersicht über weitere beliebte GUI-Bibliotheken .......................... 841

16 Werkzeuge für Programmierer ......................................................... 859

17 Shellprogrammierung ....................................................................... 951

A Sicherheit unter Linux ...................................................................... 1067

B Funktionsreferenz ............................................................................ 1087

C Linux-Unix-Kommandoreferenz ....................................................... 1151

D Inhalt der Buch-CD .......................................................................... 1223

Page 3: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

5

Inhalt

Vorwort des Autors ..................................................................................................... 23Vorwort der Fachgutachter .......................................................................................... 27

1 Einführung ........................................................................................... 29

1.1 Anforderung an den Leser ........................................................................ 291.2 Anforderung an das Betriebssystem .......................................................... 301.3 Von UNIX ... ............................................................................................. 301.4 ... zu Linux ............................................................................................... 321.5 Der Compiler GCC – eine kurze Einführung ............................................... 33

1.5.1 GCC erhöre uns – der Aufruf ...................................................... 331.5.2 Was befiehlst du – Meister? ....................................................... 341.5.3 Klassifikation der Dateitypen ..................................................... 37

1.6 POSIX, X/OPEN und ANSI C ..................................................................... 371.7 Übersicht zum Buch ................................................................................. 391.8 Schreibkonventionen ................................................................................ 411.9 Notationsstil ............................................................................................. 421.10 Weitere Hilfen .......................................................................................... 42

2 E/A-Funktionen ................................................................................... 43

2.1 Elementare E/A-Funktionen ...................................................................... 432.2 Filedeskriptor ........................................................................................... 44

2.2.1 Verwaltung für offene Deskriptoren ........................................... 452.3 Funktionen, die den Filedeskriptor verwenden ......................................... 46

2.3.1 Datei öffnen – open() ................................................................. 462.3.2 Anlegen einer neuen Datei – creat() ........................................... 512.3.3 Datei schließen – close() ............................................................ 522.3.4 Schreiben von Dateien – write() ................................................. 522.3.5 Lesen von Dateien – read() ........................................................ 552.3.6 Schreib-/Lesezeiger positionieren – lseek() ................................. 572.3.7 Duplizieren von Filedeskriptoren – dup() und dup2() ................. 592.3.8 Ändern oder Abfragen der Eigenschaften eines

Filedeskriptors – fcntl() .............................................................. 612.3.9 Record Locking – Sperren von Dateien einrichten ...................... 662.3.10 Multiplexing E/A – select() ......................................................... 752.3.11 Unterschiedliche Operationen – ioctl() ....................................... 782.3.12 Lesen und Schreiben mehrerer Puffer – writev() und readv() ...... 792.3.13 Übersicht zu weiteren Funktionen, die den

Filedeskriptor verwenden .......................................................... 80

Page 4: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

6

2.4 Standard-E/A-Funktionen ......................................................................... 842.4.1 Der FILE-Zeiger .......................................................................... 842.4.2 Öffnen und Schließen von Dateien ............................................. 852.4.3 Formatierte Ausgabe .................................................................. 862.4.4 Formatierte Eingabe ................................................................... 872.4.5 Binäres Lesen und Schreiben ...................................................... 882.4.6 Zeichen- und zeilenweise Ein-/Ausgabe ..................................... 882.4.7 Status der Ein-/Ausgabe überprüfen ........................................... 892.4.8 Stream positionieren .................................................................. 902.4.9 Puffer kontrollieren .................................................................... 912.4.10 Datei löschen und umbenennen ................................................ 922.4.11 Temporäre Dateien erstellen ...................................................... 93

2.5 Mit Verzeichnissen arbeiten ..................................................................... 942.5.1 Ein neues Verzeichnis anlegen – mkdir() ..................................... 942.5.2 In ein Verzeichnis wechseln – chdir(), fchdir() ............................ 952.5.3 Ein leeres Verzeichnis löschen – rmdir() ..................................... 972.5.4 Format eines Datei-Eintrags in struct dirent ............................... 972.5.5 Einen Verzeichnisstream öffnen – opendir() ............................... 992.5.6 Lesen aus dem DIR-Stream – opendir()

und Schließen des DIR-Streams – closedir() ................................ 1002.5.7 Positionieren des DIR-Streams ................................................... 1032.5.8 Komplettes Verzeichnis einlesen – scandir() ............................... 1042.5.9 Ganze Verzeichnisbäume durchlaufen – ftw() ............................. 108

2.6 Fehlerbehandlung ..................................................................................... 1122.7 Ausblick ................................................................................................... 114

3 Attribute von Dateien und Verzeichnissen ......................................... 115

3.1 Struktur stat ............................................................................................. 1153.1.1 Dateiart und Zugriffsrechte einer Datei erfragen – st_mode ........ 1163.1.2 User-ID-Bit und Group-ID-Bit – st_uid und st_gid ...................... 1193.1.3 Inode ermitteln – st_ino ............................................................. 1203.1.4 Linkzähler – st_nlink .................................................................. 1203.1.5 Größe der Datei – st_size ........................................................... 1243.1.6 st_atime, st_mtime, st_ctime ...................................................... 125

4 Zugriff auf Systeminformationen ........................................................ 129

4.1 Informationen aus dem /proc-Verzeichnis herausziehen ........................... 1294.2 Hardware-/Systeminformationen ermitteln ............................................... 131

4.2.1 CPU-Informationen – /proc/cpuinfo ........................................... 1314.2.2 Geräteinformationen – /proc/devices ......................................... 1324.2.3 Speicherauslastung – /proc/meminfo .......................................... 1324.2.4 Weitere Hardware-Informationen zusammengefasst .................. 132

Page 5: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

7

4.3 Prozessinformationen ............................................................................... 1354.3.1 /proc/$pid/cmdline .................................................................... 1364.3.2 /proc/$pid/environ .................................................................... 1374.3.3 /proc/self ................................................................................... 1374.3.4 /proc/$pid/fd/ ........................................................................... 1384.3.5 /proc/$pid/statm ....................................................................... 139

4.4 Kernel-Informationen ............................................................................... 1394.4.1 /proc/locks ................................................................................ 1454.4.2 /proc/modules ........................................................................... 145

4.5 Filesysteme ............................................................................................... 1464.5.1 /proc/mounts ............................................................................. 146

4.6 Weiterführendes ....................................................................................... 146

5 Devices – eine einfache Verbindung zur Hardware ............................. 149

5.1 Die Gerätedateitypen ............................................................................... 1495.2 Die Gerätedateinummern ......................................................................... 1505.3 Zugriff auf die Gerätedateien .................................................................... 1515.4 Gerätenamen ............................................................................................ 1525.5 Spezielle Gerätedateien ............................................................................ 1535.6 Gerätedateien in der Praxis einsetzen ....................................................... 154

5.6.1 CD auswerfen und wieder schließen .......................................... 1565.6.2 CD-ROM-Fähigkeiten ................................................................ 1575.6.3 Audio-CD abspielen – komplett und einzelne Tracks –

Pause, Fortfahren und Stopp ...................................................... 1575.6.4 Aktuellen Status der Audio-CD ermitteln ................................... 1615.6.5 Das komplette Listing ................................................................ 163

6 System- und Benutzerdateien ............................................................. 169

6.1 Die Datei /etc/passwd .............................................................................. 1696.1.1 Die Datei /etc/passwd auswerten ............................................... 1706.1.2 getpwuid und getpwnam – einzelne Abfrage von /etc/passwd ... 1716.1.3 getpwent, setpwent und endpwent – komplette Abfrage

von /etc/passwd ........................................................................ 1736.2 Die Datei /etc/shadow .............................................................................. 174

6.2.1 Die Datei /etc/shadow auswerten .............................................. 1756.2.2 getspent, setspent und endspent – komplette Abfrage

von /etc/shadow ........................................................................ 1766.3 Die Datei /etc/group ................................................................................ 179

6.3.1 Die Datei /etc/group auswerten ................................................. 1806.3.2 getgrnam und getgrgid – einzelne Einträge

aus /etc/group abfragen ............................................................. 180

Page 6: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

8

6.3.3 getgrent, setgrent und endgrent – alle Einträge in /etc/group abfragen ................................................................... 182

6.4 uname – Informationen zum lokalen System erfragen ............................... 1836.5 Das Verzeichnis /etc/skel und Network Information Service (NIS) ............. 1846.6 Dateien für Netzwerkinformationen .......................................................... 184

7 Dämonen, Zombies und Prozesse ....................................................... 187

7.1 Was ist ein Prozess? .................................................................................. 1877.2 Prozesskomponente ................................................................................. 188

7.2.1 Prozessnummer (PID) ................................................................ 1897.2.2 Prozessnummer des Vaterprozesses (PPID) ................................ 1897.2.3 Benutzer- und Gruppennummer eines Prozesses

(UID, EUID, GID, EGID) ............................................................. 1897.2.4 Prozessstatus ............................................................................. 1907.2.5 Prozesspriorität .......................................................................... 1917.2.6 Timesharing-Prozesse ................................................................. 1917.2.7 Prozessauslagerung .................................................................... 1957.2.8 Steuerterminal ........................................................................... 195

7.3 Prozesse überwachen – ps, top, kpm ........................................................ 1967.4 Lebenszyklus eines Prozesses .................................................................... 1987.5 Umgebungsvariablen eines Prozesses ........................................................ 200

7.5.1 Einzelne Umgebungsvariablen abfragen ..................................... 2017.5.2 Umgebungsvariable verändern oder hinzufügen –

putenv() und setenv() ................................................................. 2027.5.3 Löschen von Umgebungsvariablen – unsetenv()

und clearenv() ............................................................................ 2057.6 Ressourcenlimits eines Prozesses .............................................................. 206

7.6.1 Mehr Sicherheit mit Ressourcenlimits ........................................ 2097.7 Prozesserkennung ..................................................................................... 2097.8 Erzeugung von Prozessen – fork() .............................................................. 211

7.8.1 Pufferung ................................................................................... 2147.8.2 Was wird vererbt und was nicht? ............................................... 2187.8.3 Einen Prozess mit veränderter Priorität erzeugen ....................... 218

7.9 Warten auf einen Prozess ......................................................................... 2207.10 Die exec-Familie ....................................................................................... 226

7.10.1 execl() ........................................................................................ 2277.10.2 execve() ..................................................................................... 2287.10.3 execv() ....................................................................................... 2287.10.4 execle() ...................................................................................... 2297.10.5 execlp() ...................................................................................... 2297.10.6 execvp() ..................................................................................... 2297.10.7 Kindprozesse mit exec-Aufruf überlagern ................................... 230

Page 7: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

9

7.11 Kommandoaufrufe aus dem Programm – system() .................................... 2317.12 Dämonprozesse ........................................................................................ 232

7.12.1 Wie ein Prozess zum Dämon wird ... .......................................... 2337.12.2 Dämon, sprich mit uns ... ........................................................... 2337.12.3 Protokollieren von Dämonen – syslog() ...................................... 2347.12.4 syslog() in der Praxis .................................................................. 2367.12.5 Den Dämon, den ich rief ... ........................................................ 238

7.13 Rund um die Ausführung von Prozessen ................................................... 2427.13.1 Einen Dämon beim Booten mit einem init-Skript starten ........... 2427.13.2 Hintergrundprozesse und Jobkontrolle ....................................... 2497.13.3 Prozesse zeitgesteuert ausführen (cron-Jobs) .............................. 252

7.14 Zusammenfassung und Ausblick ............................................................... 254

8 Signale ................................................................................................. 255

8.1 Grundlage zu den Signalen ....................................................................... 2558.1.1 Signalmaske ............................................................................... 2578.1.2 Signale und fork() ...................................................................... 2578.1.3 Signale und exec ........................................................................ 2588.1.4 Übersicht zu den Signalen .......................................................... 258

8.2 Das neue Signalkonzept ............................................................................ 2608.2.1 Wozu ein »neues« Signalkonzept? .............................................. 260

8.3 Signalmenge initialisieren ......................................................................... 2608.4 Signalmenge hinzufügen oder löschen ...................................................... 2618.5 Signale einrichten oder erfragen ............................................................... 261

8.5.1 Einen Signalhandler einrichten, der zurückkehrt ......................... 2658.6 Signal an den eigenen Prozess senden – raise() ......................................... 2678.7 Signale an andere Prozesse senden – kill() ................................................. 2678.8 Zeitschaltuhr einrichten – alarm() ............................................................. 2688.9 Prozesse stoppen, bis ein Signal eintritt – pause() ..................................... 2688.10 Prozesse für eine bestimmte Zeit stoppen –

sleep() und usleep() .................................................................................. 2698.11 Signalmaske erfragen oder ändern – sigprocmask() ................................... 2698.12 Prozess während einer Änderung der Signalmaske stoppen –

sigsuspend() ............................................................................................. 2708.13 Prozesse synchronisieren .......................................................................... 271

9 IPC – Interprozesskommunikation ...................................................... 275

9.1 Unterschiedliche Interprozesskommunikations-Techniken im Überblick ............................................................................................. 2769.1.1 (Namenlose) Pipes ..................................................................... 2769.1.2 Benannte Pipes (FIFO-Pipes) ...................................................... 277

Page 8: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

10

9.1.3 Message Queue (Nachrichtenspeicher) ...................................... 2789.1.4 Semaphore ................................................................................ 2799.1.5 Shared Memory (gemeinsamer Speicher) ................................... 2799.1.6 STREAMS .................................................................................. 2809.1.7 Sockets ...................................................................................... 2819.1.8 Lock Files (Sperrdateien) ............................................................ 2819.1.9 Dateisperren (Record Locking) ................................................... 281

9.2 Gründe für IPC ......................................................................................... 2829.3 Pipes ........................................................................................................ 283

9.3.1 Eigenschaften von Pipes ............................................................. 2839.3.2 Pipes einrichten – pipe() ............................................................ 2839.3.3 Eigenschaften von elementaren E/A-Funktionen bei Pipes ......... 2879.3.4 Standard-E/A-Funktionen mit pipe ............................................ 2879.3.5 Pipes in einen anderen Prozess umleiten .................................... 2899.3.6 Filterprogramm erstellen mithilfe einer Pipe .............................. 2929.3.7 Einrichten einer Pipe zu einem anderen Prozess – popen() ......... 2959.3.8 Mail versenden mit Pipes und Sendmail ..................................... 2969.3.9 Drucken über eine Pipe mit lpr .................................................. 2999.3.10 Benannte Pipes – FIFOs ............................................................. 303

9.4 System-V-Interprozesskommunikation ...................................................... 3189.4.1 Gemeinsamkeiten der SysV-Mechanismen ................................. 3189.4.2 Ein Objekt einrichten, eine Verbindung herstellen

und das Objekt wieder löschen .................................................. 3209.4.3 Datenaustausch zwischen nicht verwandten Prozessen .............. 320

9.5 Semaphore ............................................................................................... 3219.5.1 Lebenszyklus eines Semaphors ................................................... 3219.5.2 Ein Semaphor öffnen oder erstellen – semget() .......................... 3249.5.3 Abfragen, ändern oder löschen der Semaphormenge –

semctl() ..................................................................................... 3259.5.4 Operationen auf Semaphormengen – semop() ............................ 3269.5.5 Semaphore im Vergleich mit Sperren ......................................... 328

9.6 Message Queues ...................................................................................... 3289.6.1 Eine Message Queue öffnen oder erzeugen – msgget() ............... 3299.6.2 Nachrichten versenden – msgsnd() ............................................. 3299.6.3 Eine Nachricht empfangen – msgrcv() ........................................ 3309.6.4 Abfragen, ändern oder löschen einer Message Queue –

msgctl() ..................................................................................... 3319.7 Shared Memory ........................................................................................ 339

9.7.1 Ein Shared-Memory-Segment erstellen oder öffnen – shmget() .................................................................................... 339

9.7.2 Ein Shared-Memory-Segment abfragen, ändern oder löschen – shmctl() ...................................................................... 340

Page 9: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

11

9.7.3 Ein Shared-Memory-Segment anbinden (attach) – shmat() ......... 3419.7.4 Ein Shared-Memory-Segment loslösen – shmdt() ....................... 3419.7.5 Client-Server-Beispiel – Shared Memory .................................... 342

10 Threads ................................................................................................ 349

10.1 Unterschiede zwischen Threads und Prozessen ......................................... 34910.2 Thread-Bibliotheken ................................................................................. 35010.3 Kernel- und User-Threads ......................................................................... 35110.4 Scheduling und Zustände von Threads ...................................................... 35110.5 Die grundlegenden Funktionen zur Thread-Programmierung .................... 352

10.5.1 pthread_create – einen neuen Thread erzeugen ......................... 35210.5.2 pthread_exit – einen Thread beenden ........................................ 35310.5.3 pthread_join – auf das Ende eines Threads warten ..................... 35410.5.4 pthread_self – die ID von Threads ermitteln ............................... 35410.5.5 pthread_equal – die ID von zwei Threads vergleichen ................ 35910.5.6 pthread_detach – einen Thread unabhängig machen .................. 361

10.6 Die Attribute von Threads und das Scheduling ......................................... 36210.7 Threads synchronisieren ........................................................................... 367

10.7.1 Mutexe ...................................................................................... 37010.7.2 Condition-Variablen (Bedingungsvariablen) ............................... 37710.7.3 Semaphore ................................................................................ 38710.7.4 Weitere Synchronisationstechniken im Überblick ....................... 390

10.8 Threads abbrechen (canceln) .................................................................... 39110.9 Erzeugen von Thread-spezifischen Daten (TSD-Data) ................................ 39510.10 pthread_once – Codeabschnitt einmal ausführen ...................................... 39810.11 Thread-safe (thread-sichere Funktionen) ................................................... 40010.12 Threads und Signale ................................................................................. 40110.13 Zusammenfassung und Ausblick ............................................................... 405

11 Netzwerkprogrammierung .................................................................. 407

11.1 Einführung ............................................................................................... 40711.2 Aufbau von Netzwerken ........................................................................... 408

11.2.1 ISO/OSI und TCP/IP – Referenzmodell ....................................... 40811.2.2 Das World Wide Web (Internet) ................................................ 410

11.3 TCP/IP – Aufbau und Struktur ................................................................... 41111.3.1 Netzwerkschicht (Datenübertragung) ......................................... 41211.3.2 Internetschicht .......................................................................... 41211.3.3 Transportschicht (TCP, UDP) ...................................................... 41211.3.4 Anwendungsschicht ................................................................... 413

11.4 TCP Socket ............................................................................................... 41411.5 Kommunikationsmodell ............................................................................ 415

Page 10: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

12

11.6 Grundlegende Funktionen zum Zugriff auf die Socket-Schnittstelle ........... 41611.6.1 Ein Socket anlegen – socket() ..................................................... 41611.6.2 Verbindungsaufbau – connect() .................................................. 41811.6.3 Socket mit einer Adresse verknüpfen – bind() ............................ 42011.6.4 Auf Verbindungen warten – listen() und accept() ....................... 42111.6.5 Senden und empfangen von Daten (1) – write() und read() ........ 42211.6.6 Senden und empfangen von Daten (2) – send() und recv() ......... 42211.6.7 Verbindung schließen – close() ................................................... 423

11.7 Aufbau eines Clientprogramms ................................................................. 42411.7.1 Zusammenfassung Clientanwendung und Quellcode .................. 426

11.8 Aufbau des Serverprogramms ................................................................... 42711.8.1 Zusammenfassung: Serveranwendung und Quellcode ............... 429

11.9 IP-Adressen konvertieren, manipulieren und extrahieren .......................... 43211.9.1 inet_aton(), inet_pton() und inet_addr() ..................................... 43211.9.2 inet_ntoa() und inet_ntop() ........................................................ 43311.9.3 inet_network() ........................................................................... 43411.9.4 inet_netof() ................................................................................ 43511.9.5 inet_lnaof() ................................................................................ 43511.9.6 inet_makeaddr() ........................................................................ 435

11.10 Namen und IP-Adressen umwandeln ........................................................ 43811.10.1 Name-Server .............................................................................. 43911.10.2 Informationen zum Rechner im Netz – gethostbyname

und gethostbyaddr .................................................................... 43911.10.3 Service-Informationen – getservbyname() und getservbyport() ... 443

11.11 Der Puffer ................................................................................................. 44611.12 Standard-E/A-Funktionen verwenden ....................................................... 447

11.12.1 Pufferung von Standard-E/A-Funktionen .................................... 44811.13 Parallele Server ......................................................................................... 44811.14 Syncrones Multiplexing – select() .............................................................. 46211.15 POSIX-Threads und Netzwerkprogrammierung ......................................... 48111.16 Optionen für Sockets setzen bzw. erfragen ............................................... 485

11.16.1 setsockopt() ............................................................................... 48611.16.2 getsockopt() .............................................................................. 48611.16.3 Socket-Optionen ....................................................................... 486

11.17 UDP ......................................................................................................... 48911.17.1 Clientanwendung ....................................................................... 49111.17.2 Serveranwendung ...................................................................... 49211.17.3 recvfrom() und sendto() ............................................................. 49211.17.4 bind() verwenden oder weglassen .............................................. 496

11.18 Unix-Domain-Sockets (IPC) ...................................................................... 49611.18.1 Die Adressstruktur von Unix-Domain-Sockets ............................ 49711.18.2 Lokale Sockets erzeugen – socketpair() ....................................... 500

Page 11: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

13

11.19 Multicast-Socket ...................................................................................... 50211.19.1 Anwendungsgebiete von Multicast-Verbindungen ..................... 509

11.20 Nicht blockierende I/O-Sockets ................................................................ 50911.21 Etwas zu Streams und TLI, Raw Socket, XTI .............................................. 512

11.21.1 Raw Socket ................................................................................ 51211.21.2 TLI und XTI ................................................................................ 51311.21.3 RPC (Remote Procedure Call) ..................................................... 513

11.22 IPv4 und IPv6 ........................................................................................... 51411.22.1 IPv6 – ein wenig genauer ........................................................... 515

11.23 Netzwerksoftware nach IPv6 portieren ..................................................... 51511.23.1 Konstanten ................................................................................ 51511.23.2 Strukturen ................................................................................. 51611.23.3 Funktionen ................................................................................ 516

11.24 Sicherheit und Verschlüsselung ................................................................. 517

12 MySQL und PostgreSQL ...................................................................... 519

12.1 Relationales Datenbanksystem ................................................................. 51912.2 Relationaler Datenbankserver ................................................................... 52112.3 SQL-Server im Überblick ........................................................................... 52212.4 MySQL ..................................................................................................... 522

12.4.1 Anwendungsgebiete von MySQL ............................................... 52312.4.2 Schnittstellen von MySQL .......................................................... 52412.4.3 Installation von MySQL ............................................................. 52412.4.4 MySQL-Server starten und stoppen ........................................... 52412.4.5 Konfigurationsdatei my.cnf ........................................................ 52512.4.6 Kommandozeilenwerkzeuge für und von mysql ......................... 52612.4.7 Grafische Clients ........................................................................ 53012.4.8 MySQL-Crashkurs ...................................................................... 53012.4.9 Datentypen ............................................................................... 53112.4.10 Datenbank anlegen, verwenden und löschen ............................. 53412.4.11 Tabelle anlegen ......................................................................... 53512.4.12 Schlüsselfelder (Tabellen anlegen) .............................................. 53612.4.13 Indices ....................................................................................... 53712.4.14 Tabellentypen (Tabellen anlegen) ............................................... 53812.4.15 Autowerte definieren ................................................................. 53812.4.16 Tabellen umbenennen und ändern ............................................. 53812.4.17 Daten einfügen, ändern und löschen .......................................... 54012.4.18 Daten importieren ..................................................................... 54212.4.19 Datenausgabe ............................................................................ 54312.4.20 NULL ist 0 oder undefiniert? ...................................................... 54512.4.21 Unscharfe Suche ........................................................................ 545

Page 12: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

14

12.5 MySQL C-API ........................................................................................... 54612.5.1 Verbindung mit dem MySQL-Server aufbauen ........................... 54712.5.2 Aufgetretene Fehler ermitteln – mysql_errno() und

mysql_error() ............................................................................. 54912.5.3 Schließt die Verbindung zum Server – mysql_close() .................. 55012.5.4 Erstes Beispiel ............................................................................ 55012.5.5 Verschiedene Informationen ermitteln ....................................... 55512.5.6 Datenbanken, Tabellen und Felder ausgeben (MYSQL_RES) ....... 55812.5.7 Ergebnismenge zeilenweise bearbeiten (MYSQL_ROW) ............. 56012.5.8 Ergebnismenge spaltenweise einlesen (und ausgeben)

(MYSQL_FIELD) ......................................................................... 56212.5.9 Ein Beispiel ................................................................................ 56612.5.10 Ergebnismenge – weitere Funktionen ......................................... 57212.5.11 Befehle an den Server – mysql_query() und

mysql_real_query() ..................................................................... 57312.5.12 Weitere Funktionen ................................................................... 57712.5.13 Veraltete Funktionen ................................................................. 582

12.6 Beispiel eines Newssystems mit MySQL .................................................... 58312.6.1 Die Headerdatei my_cgi.h .......................................................... 58412.6.2 (Pseudo-)Planung ...................................................................... 58912.6.3 Datenbank und Tabellen anlegen ............................................... 58912.6.4 MySQL-Clients mit GUI ............................................................. 60812.6.5 Randnotiz .................................................................................. 609

12.7 Neue SQL-Funktionen für die Shell – MySQL erweitern ............................ 60912.8 MySQL-Funktionen mit der UDF-Schnittstelle entwerfen ......................... 610

12.8.1 UDF-Sequenzen ......................................................................... 61212.8.2 UDF_INIT-Struktur ..................................................................... 61212.8.3 UDF_ARGS-Struktur ................................................................... 61312.8.4 Rückgabewert ............................................................................ 61412.8.5 Benutzerdefinierte Funktionen erstellen ..................................... 61512.8.6 Benutzerdefinierte Funktion kompilieren, installieren

und ausführen ............................................................................ 61712.9 PostgreSQL – objektrelationales Datenbankverwaltungssystem ................. 619

12.9.1 PostgreSQL im Vergleich zu MySQL ........................................... 61912.9.2 Unterschiede in der Syntax zwischen MySQL und PostgreSQL ... 62012.9.3 PostgreSQL installieren .............................................................. 62112.9.4 Konfigurationsdateien bei PostgreSQL –

(postgresql.conf, pg_hba_conf) .................................................. 62212.9.5 CRASHKURS PostgreSQL ........................................................... 62412.9.6 PostgreSQL C-API – libpg ........................................................... 63112.9.7 Umgebungsvariablen und Passwortdatei .................................... 65112.9.8 PostgreSQL und Threads ............................................................ 65212.9.9 Ausblick ..................................................................................... 652

Page 13: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

15

13 Terminal E/A und Benutzerschnittstellen für die Konsole .................. 653

13.1 termios ..................................................................................................... 65313.1.1 Terminalattribute bearbeiten ..................................................... 65413.1.2 Flags setzen und löschen ............................................................ 65913.1.3 Terminalidentifizierung .............................................................. 66513.1.4 Geschwindigkeitskontrolle – Baudrate von Terminals

einstellen ................................................................................... 66713.2 terminfo ................................................................................................... 671

13.2.1 terminfo verwenden .................................................................. 67213.2.2 terminfo initialisieren – setupterm() ........................................... 67313.2.3 Eigenschaften eines Terminals (Finden von capnames) –

tigetflag(), tigetnum() und tigetstr() ............................................ 67413.2.4 Mit terminfo-Eigenschaften arbeiten – putp(), tputs(), tparm() ... 677

13.3 ncurses – Halbgrafik .................................................................................. 67913.3.1 ncurses initialisieren ................................................................... 68013.3.2 Tastaturmodus und Ein- und Ausgabe ........................................ 68113.3.3 Eigenschaft der Fenster .............................................................. 69113.3.4 Scrolling .................................................................................... 69313.3.5 Attribute und Farben setzen ...................................................... 69613.3.6 Fensterroutinen ......................................................................... 70013.3.7 Mausprogrammierung mit ncurses ............................................. 706

14 GTK+ .................................................................................................... 715

14.1 Was ist GTK+? .......................................................................................... 71514.1.1 Was sind GDK und Glib? ............................................................ 71614.1.2 Schnittstellen von GTK+ zu anderen Programmiersprachen ........ 71714.1.3 GTK+ und GNOME .................................................................... 71714.1.4 GTK+ Version 1.2 und 2.x .......................................................... 71714.1.5 GTK+ – Aufbau des Kapitels ....................................................... 718

14.2 GTK+-Anwendungen übersetzen .............................................................. 71914.3 Eine Einführung in die Glib-Bibliothek ...................................................... 720

14.3.1 Datentypen ............................................................................... 72014.3.2 Routinen ................................................................................... 72114.3.3 Assertions-Funktionen ............................................................... 72314.3.4 Speicherverwaltung ................................................................... 72514.3.5 Stringbearbeitung ...................................................................... 72714.3.6 Selbstverwaltender Stringpuffer ................................................. 73114.3.7 Timer ......................................................................................... 73414.3.8 Dynamische Arrays .................................................................... 73614.3.9 Listen, Hashtabellen und binäre Bäume ..................................... 74014.3.10 Ausblick Glib ............................................................................. 740

Page 14: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

16

14.4 Grundlagen der GTK+-Programmierung .................................................... 74114.4.1 Die Umgebung initialisieren ....................................................... 74114.4.2 Widgets erzeugen und ggf. die Attribute setzen ......................... 74214.4.3 Eine Callback-Funktion einrichten, um Events abzufangen ......... 74314.4.4 Eine GTK+-Anwendung beenden ............................................... 74514.4.5 Die hierarchische Anordnung der Widgets definieren ................. 74714.4.6 Widgets anzeigen ...................................................................... 74814.4.7 Signale und Events abfangen und bearbeiten –

(Events-)Verarbeitungsschleife ................................................... 74814.4.8 GTK+ und Umlaute (Zeichenkodierung) ..................................... 749

14.5 Fenster – GtkWindow ............................................................................... 75014.5.1 Dialogfenster (Dialogboxen) ....................................................... 75314.5.2 GtkMessageDialog ..................................................................... 757

14.6 Anzeige-Elemente .................................................................................... 75814.6.1 Text – GtkLabel .......................................................................... 76014.6.2 Trennlinie – GtkSeparator .......................................................... 76314.6.3 Grafiken – GtkImage .................................................................. 76414.6.4 Statusleiste – GtkStatusbar ......................................................... 76414.6.5 Fortschrittsbalken – GtkProgressBar ........................................... 765

14.7 Behälter .................................................................................................... 76514.7.1 Boxen – GtkBox ......................................................................... 76514.7.2 Aufteilungen, Register und Button-Box ...................................... 76714.7.3 Tabellen – GtkTable ................................................................... 77314.7.4 Ausrichtung – GtkAlignment ...................................................... 776

14.8 Buttons und Toogled-Buttons ................................................................... 77714.8.1 Buttons allgemein ...................................................................... 78314.8.2 Radio-Buttons (GtkRadioButton) ................................................ 78314.8.3 GtkRadioButton, GtkCheckButton und GtkToggleButton ........... 78414.8.4 Signale für Buttons (GtkButton) ................................................. 784

14.9 Dateneingabe ........................................................................................... 78514.9.1 Textfelder – GtkEntry ................................................................. 79114.9.2 Schieberegler – GtkScale ............................................................ 79214.9.3 Zahlenfelder – GtkSpinButton .................................................... 79314.9.4 Einstellungen – GtkAdjustment .................................................. 79414.9.5 GtkEditable ................................................................................ 795

14.10 Menü und Toolbar ................................................................................... 79514.10.1 Menü – GtkItemFactory ............................................................. 80014.10.2 Toolbar – GtkToolbar ................................................................. 80514.10.3 Options-Menü – GtkOptionsMenu ............................................ 80814.10.4 Combo-Boxen – GtkCombo ....................................................... 808

14.11 Mehrzeiliger Text ..................................................................................... 81214.11.1 Text(editor) – GtkTextView, GtkTextBuffer ................................. 82014.11.2 Scrollendes Fenster – GtkScrolledWindow ................................. 823

Page 15: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

17

14.12 Auswählen (Selection) .............................................................................. 82414.12.1 Dateiauswahl – GtkFileSelection ................................................ 831

14.13 Events ...................................................................................................... 83314.14 Weitere Widget- und GTK+-Elemente im Überblick ................................. 838

14.14.1 Bäume und Listen ...................................................................... 83814.14.2 Lineale ....................................................................................... 83914.14.3 Zwischenablage (Clipboard) ....................................................... 83914.14.4 Drag and Drop ........................................................................... 83914.14.5 Stock Items – Repertoire-Einträge .............................................. 83914.14.6 Signale ....................................................................................... 83914.14.7 Ressource-Files .......................................................................... 83914.14.8 Widget-Entwicklung .................................................................. 83914.14.9 GDK .......................................................................................... 840

15 Übersicht über weitere beliebte GUI-Bibliotheken ............................ 841

15.1 gtkmm – GTK+ für C++ ............................................................................. 84115.1.1 Programmbeispiel ...................................................................... 84215.1.2 GUI-Designer GLADE für GTK+ und gtkmm ............................... 844

15.2 wxWidget ................................................................................................. 84515.2.1 Programmbeispiel ...................................................................... 84515.2.2 GUI-Designer wxFormBuilder .................................................... 847

15.3 FLTK ......................................................................................................... 84815.3.1 Programmbeispiel ...................................................................... 84815.3.2 GUI-Designer FLUID .................................................................. 849

15.4 Qt ............................................................................................................ 84915.4.1 Programmbeispiel ...................................................................... 85015.4.2 Der GUI-Designer von Qt .......................................................... 851

15.5 Die niedrige Ebene – X-Window-Programmierung .................................... 85215.6 Multimediabibliotheken ........................................................................... 852

15.6.1 SDL ........................................................................................... 85215.6.2 Allegro ...................................................................................... 85315.6.3 OpenGL (bzw. Mesa 3D) ........................................................... 85415.6.4 Programmbeispiel ...................................................................... 855

16 Werkzeuge für Programmierer ............................................................ 859

16.1 Der Compiler gcc ...................................................................................... 85916.1.1 Standardgebrauch des gcc ......................................................... 86116.1.2 Linken von Programmbibliotheken ............................................ 86116.1.3 Dateien, die GCC kennt ............................................................. 86216.1.4 Ausgabedateien bei jedem einzelnen Schritt der

Übersetzung erstellen ................................................................ 863

Page 16: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

18

16.1.5 Noch mehr Optionen ................................................................. 86416.1.6 Optionen für Warnmeldungen ................................................... 86416.1.7 Präprozessor-Optionen .............................................................. 86516.1.8 Debuggen und Profiling ............................................................. 86516.1.9 Optimierungsflags ...................................................................... 865

16.2 Make ........................................................................................................ 86616.2.1 Erzeugen eines Makefiles ........................................................... 86816.2.2 Variablen, Makros und Abkürzungen ......................................... 87416.2.3 Implizite Regeln ......................................................................... 87616.2.4 Musterregeln ............................................................................. 87816.2.5 make zur Installation verwenden ................................................ 87816.2.6 make-Optionen ......................................................................... 87916.2.7 Ausblick ..................................................................................... 880

16.3 Bibliotheken erstellen ............................................................................... 88016.3.1 Statische Bibliotheken erstellen ................................................. 88016.3.2 Dynamische Bibliotheken (Shared Libraries) erstellen ................. 88316.3.3 Dynamisches Nachladen von Bibliotheken ................................. 886

16.4 RPM ......................................................................................................... 88816.4.1 Einführung in RPM .................................................................... 88916.4.2 Verzeichnisse, die RPM benötigt ................................................ 89016.4.3 Ein eigenes RPM-Paket erstellen ................................................ 89116.4.4 Sources ...................................................................................... 89116.4.5 Die Spec-Datei .......................................................................... 89216.4.6 Paket erstellen ........................................................................... 89516.4.7 Das Paket installieren ................................................................. 897

16.5 RCS und CVS ............................................................................................ 89816.5.1 Software-Configuration-Management-Systeme (SCM) ................ 89916.5.2 RCS ............................................................................................ 89916.5.3 CVS ........................................................................................... 908

16.6 Zeitmessung von Programmen .................................................................. 92316.6.1 Einfache Zeitmessung mit TIME – Laufzeit von Prozessen ........... 92316.6.2 Profiling mit GPROF – Laufzeit von Funktionen .......................... 92416.6.3 Analyse mit GCOV ..................................................................... 927

16.7 Debuggen mit gdb und ddd ..................................................................... 92916.8 STRACE – Systemaufrufe verfolgen ............................................................ 93916.9 Memory Leaks und unerlaubte Speicherzugriffe ........................................ 942

16.9.1 efence ........................................................................................ 94216.9.2 valgrind ..................................................................................... 945

16.10 Ausblick ................................................................................................... 948

Page 17: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

19

17 Shellprogrammierung .......................................................................... 951

17.1 Was ist eine Shell und was kann sie? ........................................................ 95117.2 Was sind Shellskripts und wann ist ihr Einsatz sinnvoll? ............................ 95117.3 Wann brauche ich keine Shellskripts? ....................................................... 95317.4 Verschiedene Shelltypen ........................................................................... 953

17.4.1 Erweiterungen der Bourne-Shell (sh) .......................................... 95417.4.2 Erweiterung der C-Shell (csh) ..................................................... 95517.4.3 Welche Shell sollte man kennen? ............................................... 955

17.5 Shellskripts ausführen ............................................................................... 95517.5.1 Shellskript im Hintergrund ausführen ......................................... 95617.5.2 Die Bedeutung der Subshell ....................................................... 95617.5.3 Die ausführende Shell festlegen ................................................. 95817.5.4 Shellskript beenden ................................................................... 963

17.6 Vom Shellskript zum Prozess .................................................................... 96417.7 Datenstrom (Stream) umleiten .................................................................. 965

17.7.1 Standardausgabe umleiten ......................................................... 96517.7.2 Standardfehlerausgabe umleiten ................................................ 96617.7.3 Standardausgabe und Standardfehlerausgabe verknüpfen .......... 96717.7.4 Standardeingabe umleiten ......................................................... 96817.7.5 Pipes ......................................................................................... 96917.7.6 Standardausgabe in zwei Richtungen mit tee ............................. 97017.7.7 Zusammenfassung der verschiedenen Umlenkungen .................. 971

17.8 Ersatzmuster (Namen-Expansion) zur Suche verwenden ............................ 97217.8.1 Beliebige Zeichenfolge * (Asterisk) ............................................. 97217.8.2 Beliebiges Zeichen ? ................................................................... 97317.8.3 Zeichenbereiche einschränken ................................................... 97317.8.4 Brace Extension (nur Bash und Korn-Shell) ................................. 97417.8.5 Tilde-Expansion (nur Bash und Korn-Shell) ................................ 97517.8.6 Zusammenfassung zu den Ersatzmustern .................................... 975

17.9 Variablen .................................................................................................. 97617.9.1 Zahlen ....................................................................................... 97917.9.2 Zeichenketten ............................................................................ 98417.9.3 Arrays (nur Bash und Korn-Shell) ............................................... 98917.9.4 Variablen exportieren ................................................................ 99117.9.5 Die Umgebungsvariablen (Shellvariablen) .................................. 99417.9.6 Auto-Variablen der Shell ............................................................ 995

17.10 Quotings .................................................................................................. 99717.10.1 Single und Double Quotings ...................................................... 99717.10.2 Kommandosubstitution (Back Quotes) ....................................... 998

17.11 Kommandozeilenargumente ..................................................................... 99917.11.1 Kommandozeilenparameter $1 bis $9 ........................................ 100017.11.2 Variable Anzahl von Parametern auswerten ............................... 1001

Page 18: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

20

17.11.3 Die Anzahl der Argumente überprüfen ....................................... 100117.11.4 Der Befehl shift .......................................................................... 100217.11.5 Argumente für die Kommandozeile setzen – set ......................... 100317.11.6 Kommandozeilenoptionen auswerten ........................................ 1004

17.12 Kontrollstrukturen .................................................................................... 100617.12.1 Die if-Anweisung ....................................................................... 100617.12.2 Die else-Alternative für die if-Verzweigung ................................ 101017.12.3 Mehrfache Alternative mit elif ................................................... 101017.12.4 Das Kommando test .................................................................. 101117.12.5 Dateistatus ermitteln ................................................................. 101517.12.6 Ausdrücke logisch verknüpfen .................................................... 101717.12.7 Verzweigungen mit case ............................................................ 102017.12.8 Schleifen .................................................................................... 1022

17.13 Terminal-Eingabe und -Ausgabe ............................................................... 102817.13.1 Ausgabe ..................................................................................... 102817.13.2 Eingabe ..................................................................................... 103117.13.3 Umlenkungen mit exec und File-Deskriptoren erzeugen ............. 104317.13.4 Named Pipes ............................................................................. 104617.13.5 Menü mit select (nur Bash und Korn-Shell) ................................ 1047

17.14 Funktionen ............................................................................................... 105017.14.1 Funktionsaufruf .......................................................................... 105017.14.2 Externe Funktionen verwenden .................................................. 105017.14.3 Parameterübergabe .................................................................... 105117.14.4 Rückgabewert aus einer Funktion .............................................. 1052

17.15 Signale ..................................................................................................... 105417.15.1 Signale senden ........................................................................... 105417.15.2 Signale in einem Shellskript abfangen – trap .............................. 105517.15.3 Signal-Handler einrichten ........................................................... 105617.15.4 Signale ignorieren oder zurücksetzen ......................................... 1057

17.16 Prozess- und Skriptausführung .................................................................. 105817.16.1 Auf Prozesse warten .................................................................. 105817.16.2 Hintergrundprozess hervorholen ................................................ 105817.16.3 Jobverwaltung ........................................................................... 105917.16.4 Explizite Subshell verwenden ..................................................... 106017.16.5 Kommunikation zwischen Shellskripten ..................................... 106117.16.6 Skripte zeitgesteuert ausführen .................................................. 1065

17.17 Ein Shellskript bei der Ausführung ............................................................ 1065

Anhang ....................................................................................................... 1067

A Sicherheit unter Linux .......................................................................................... 1067A.1 Viren und Trojaner ................................................................................... 1067A.2 Der Superuser (su) .................................................................................... 1068

Page 19: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

21

A.3 Überlaufen von Logfiles ............................................................................ 1068A.4 Zugriffsrechte auf Dateien ........................................................................ 1069A.5 Das SUID-Bit ............................................................................................ 1069A.6 Programme ohne Ausführrechte ............................................................... 1071A.7 Buffer Overflow (Pufferüberlauf) ............................................................... 1071A.8 Race Condition ......................................................................................... 1073A.9 Temporäre Dateien ................................................................................... 1074A.10 chroot ...................................................................................................... 1075A.11 Umgebungsvariablen ................................................................................ 1076A.12 Zugriffsrechte – häufig gemachte Fehler .................................................... 1079A.13 system() und popen() ................................................................................ 1079A.14 Offene Filedeskriptoren ............................................................................ 1080A.15 Core Dump .............................................................................................. 1082A.16 SQL Injection ........................................................................................... 1083A.17 Filedeskriptor-Überlauf mit select() ........................................................... 1085

B Funktionsreferenz ................................................................................................ 1087B.1 ANSI C ..................................................................................................... 1087B.2 ANSI C99 ................................................................................................. 1105B.3 Elementare E/A-Funktionen ...................................................................... 1112B.4 Fortgeschrittene E/A-Funktionen .............................................................. 1114B.5 Verzeichnisse ............................................................................................ 1120B.6 Attribute von Dateien und Verzeichnissen ................................................ 1122B.7 Links ........................................................................................................ 1124B.8 Prozess und Prozessverwaltungsfunktionen .............................................. 1125B.9 Signale – Das neue Signalkonzept ............................................................. 1126B.10 Interprozesskommunikationen .................................................................. 1129B.11 Sys-V-Interprozesskommnunikationen ...................................................... 1130B.12 Threadprogrammierung ............................................................................ 1132B.13 Netzwerkprogrammierung ........................................................................ 1135B.14 MySQL C-API ........................................................................................... 1141B.15 PostgreSQL C-API ..................................................................................... 1146B.16 Weitere Funktionsreferenzen auf der Buch-CD ......................................... 1149

C Linux-Unix-Kommandoreferenz ............................................................................ 1151C.1 Dateiorientierte Kommandos .................................................................... 1151C.2 Verzeichnisorientierte Kommandos .......................................................... 1168C.3 Verwaltung von Benutzern und Gruppe .................................................... 1169C.4 Programm- und Prozessverwaltung ........................................................... 1173C.5 Speicherplatzinformationen ...................................................................... 1179C.6 Dateisystem-Kommandos ......................................................................... 1180C.7 Archivierung und Backup .......................................................................... 1190C.8 Systeminformationen ................................................................................ 1202C.9 System-Kommandos ................................................................................. 1203

Page 20: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Inhalt

22

C.10 Druckeradministration .............................................................................. 1205C.11 Netzwerkbefehle ...................................................................................... 1205C.12 Benutzerkommunikation .......................................................................... 1216C.13 Bildschirm- und Terminalkommandos ....................................................... 1217C.14 Online-Hilfen ........................................................................................... 1219C.15 Alles rund um PostScript-Kommandos ...................................................... 1221C.16 Gemischte Kommandos ............................................................................ 1221

D Inhalt der Buch-CD .............................................................................................. 1223

Index ........................................................................................................................... 1225

Page 21: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

129

Das /proc-(Pseudo-)Filesystem beinhaltet eine Menge Informationen zu Ihrem System. Ob Sie nun Informationen zum aktuellen Prozess, zur Hardware in Ihrem System oder zum Kernel benötigen, all dies finden Sie im /proc-Filesystem.

4 Zugriff auf Systeminformationen

Da der Kernel den kompletten Rechner verwaltet, besitzt dieser auch eine Menge Informatio-nen zum System, auf dem dieser läuft. Diese Informationen werden vom Kernel in Pseudo-Dateien und Pseudo-Verzeichnissen angelegt. All diese Dateien liegen im /proc-Verzeichnis.Auf die Einträge im /proc-Verzeichnis können Sie wie auf gewöhnliche Dateien zugreifen;meistens allerdings nur lesend. Dieses (Pseudo-)Dateisystem belegt keinerlei Plattenplatz undbefindet sich im Hauptspeicher (RAM). Sie können sich gerne einen Überblick zum /proc-Verzeichnis verschaffen.

$ ls -l /proc | less

Auf alle diese Informationen können Sie (fast) ohne weiteres lesend zugreifen. Wollen Sie z. B.den aktuellen Kernel Ihres Systems ermitteln und ausgeben lassen, können Sie auf die Datei/proc/version zugreifen:

$ cat /proc/versionLinux version 2.6.27-7-generic (buildd@palmer)(gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu11))#1 SPM Tue Jan 4 19:33:20 UTC 2009

Schon erhalten Sie die aktuelle Kernel-Version, das Datum, an dem dieser kompiliert wurde,und die Version des zugehörigen Compilers als String zurück.

4.1 Informationen aus dem /proc-Verzeichnis herausziehen

Als Programmierer dürfte Sie in erster Linie interessieren, wie Sie mit Ihrem Programm andiese Informationen kommen. Als Beispiel dient hier die Speicherauslastung des Systems.Hierbei soll lediglich ermittelt werden, wie viel RAM insgesamt auf Ihrem System zur Verfü-gung steht. Diese Informationen erhalten Sie aus /proc/meminfo:

$ cat /proc/meminfoMemTotal: 514296 kBMemFree: 10428 kBBuffers: 122940 kBCached: 120112 kBSwapCached: 1152 kBActive: 337336 kB

Page 22: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

130

4

Inactive: 122512 kBHighTotal: 0 kBHighFree: 0 kBLowTotal: 514296 kBLowFree: 10428 kBSwapTotal: 409616 kBSwapFree: 385128 kB...

Uns interessiert hier der Wert »MemTotal«. Der einfachste Weg, diesen Wert auszulesen, istes, /proc/meminfo mit fopen() zu öffnen, in einen Puffer einzulesen und nach der Stringfolge»MemTotal« zu suchen. Anschließend kann der Wert mit der sscanf() aus dem Puffer in einedafür vorgesehene Variable übergeben werden. Hier das mögliche Beispiel:

/* memory.c */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>

static long get_mem_total (void) {FILE *fp;char buffer[1024];size_t bytes_read;char *match;long mem_tot;

if((fp = fopen("/proc/meminfo", "r")) == NULL) {perror("fopen()");exit(EXIT_FAILURE);

}

bytes_read = fread (buffer, 1, sizeof (buffer), fp);fclose (fp);if (bytes_read == 0 || bytes_read == sizeof (buffer))

return 0;buffer[bytes_read] = '\0';/* Suchen nach der Stringfolge "Memtotal" */match = strstr (buffer, "MemTotal");if (match == NULL) /* Nicht gefunden */

return 0;sscanf (match, "MemTotal: %ld", &mem_tot);return (mem_tot/1024); /* 1MB = 1024KB */

}

int main (void) {long memory = get_mem_total();if(memory == 0)

printf("Konnte RAM nicht ermitteln\n");else

Page 23: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Hardware-/Systeminformationen ermitteln 4.2

131

printf("Vorhandener Arbeitsspeicher: %ldMB\n" ,memory);return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o memory memory.c$ ./memoryVorhandener Arbeitsspeicher: 249MB

So oder so ähnlich können Sie in der Regel bei allen Informationen vorgehen, die Sie im/proc-Verzeichnis finden und benötigen. Sie sollten allerdings darauf achten, dass sich derName des Eintrags im /proc-Verzeichnis bei neueren Kernel-Versionen ändern könnte. Sokönnte vielleicht in absehbarer Zeit aus /proc/meminfo /proc/more_meminfo (nur ein Bei-spiel) werden. Bedenken Sie dies, wenn Sie Ihr Programm auf dem Stand der Zeit halten wol-len.

4.2 Hardware-/Systeminformationen ermitteln

Viele Einträge im /proc-Filesystem erlauben Ihnen, Informationen zur Hardware des Systemszu ermitteln. Das sind interessante Informationen für Systemadministratoren und auch fürden Programmierer von Programmen. Hier einige häufig verwendete Einträge im Überblick.

4.2.1 CPU-Informationen – /proc/cpuinfo

/proc/cpuinfo beinhaltet Informationen zur CPU (Prozessor) oder zu den CPUs, die aufIhrem System laufen. Ausgegeben wird dabei die Anzahl der Prozessoren. Ist der Wert von»processor« wie im Beispiel 0, so kann dies bedeuten, dass es sich um ein Single-Prozessor-System handelt.

Weitere Daten finden Sie zu der CPU-Familie, dem Modell, der Frequenz, der Revision undnoch einigem mehr. Hierzu ein Ausschnitt aus meinem System:

$ cat /proc/cpuinfoprocessor : 0vendor_id : GenuineIntel

Hinweis

Bei diesem Buch handelt es sich nicht um ein Buch zur Erklärung von Hardware. Sollten Sie keinerleiKenntnisse vom Innenleben Ihres PC haben, dann wäre zusätzliche Literatur recht sinnvoll.

Hinweis

Auf SMP (Multi-CPU-Maschinen) ist der Wert von processor ... nicht direkt 0, sondern es wird fürjeden Prozessor einzeln »processor, vendor_id« etc. angezeigt, weshalb »auf 0 gesetzt« nicht ganzkorrekt ist.

Page 24: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

132

4

cpu family : 15model : 2model name : Intel(R) Pentium(R) 4 CPU 1.60GHzstepping : 4cpu MHz : 1594.865cache size : 512 KBfdiv_bug : nohlt_bug : nof00f_bug : nocoma_bug : nofpu : yesfpu_exception : yescpuid level : 2wp : yesflags : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat

pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tmbogomips : 3185.04

Für mehr Informationen zur CPU sei die Dokumentation zu cpuid des Intel Architecture Soft-ware Developers Manual, Volume 2, empfohlen.

4.2.2 Geräteinformationen – /proc/devices

Hier sind Informationen zu allen verfügbaren Geräten (zeichen- und blockorientiert) wie derFestplatte, dem Diskettenlaufwerk, der seriellen und parallelen Schnittstelle usw. aufgelistet.

4.2.3 Speicherauslastung – /proc/meminfo

(S. o. unter 4.1.) In dieser Pseudo-Datei kann der aktuelle Speicherstatus ausgelesen werden.Angezeigt werden der vorhandene und der belegte Speicher (sowohl der physikalische alsauch der Swap-Speicher). Ebenfalls lässt sich ermitteln, wie viel davon für geteilten Speicher(Shared Memory), Puffer und Caches belegt ist, die der Kernel benutzt.

4.2.4 Weitere Hardware-Informationen zusammengefasst

Es gibt natürlich noch eine Menge mehr Informationen zur Hardware im /proc-Verzeichnis,die allerdings zum Teil auch von der Konfiguration des Systems abhängt. Hierzu eine kleineZusammenfassung zu weiteren gängigen Einträgen im /proc-Verzeichnis.

Verzeichniseintrag Bedeutung

/proc/dma Liste von belegten DMA-Kanälen, die für einen Treiber reserviert sind, und der Name des Treibers

/proc/interrupts Liste der benutzten Interrupts mit Anzahl der passierten Interrupts seit System-start, Typ des Interrupts und Angabe, durch welche Module dieser Interrupt ver-wendet wird

Tabelle 4.1 Systeminformationen im /proc-Verzeichnis

Page 25: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Hardware-/Systeminformationen ermitteln 4.2

133

Das folgende Listing soll Ihnen jetzt demonstrieren, wie einfach es ist, aus dem System nütz-liche Informationen zur Hardware ausgeben zu lassen. Das Beispiel stellt eine einfacheSchnittstelle dar, die es zu erweitern gilt. Damit haben Sie schon die Grundlage für ein Sys-temprogramm zur Hand. Sollte es ein Konsolenprogramm werden, dann müssten Sie die Aus-gabe benutzerfreundlich anpassen; ebenfalls dann, wenn Sie nur einzelne Informationen aus-geben wollen. Natürlich können Sie über das Programm auch ein grafisches Frontend ziehen.Denn auch die Systemprogramme von KDE oder GNOME machen nichts anderes, als dieDaten aus dem /proc-Filesystem zu lesen und entsprechend auszugeben.

/* myinfo.c */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#define BUF 4096 /* Anpassen */

enum { CPU, DEV, DMA, INT, IOP, MEM, VERS, SCSI, EXIT };

static const char *info[] = {"/proc/cpuinfo", "/proc/devices", "/proc/dma","/proc/interrupts", "/proc/ioports", "/proc/meminfo","/proc/version", "/proc/scsi/scsi"

};

static void get_info (const int inf) {FILE *fp;

/proc/ioports Eine Liste aller belegten IO-Ports für die Ein-/Ausgabe wie die Festplatte, Ether-net, Soundkarte, Modem, USB etc. (gemappte Hardware-Speicherbereiche fin-den sich in /proc/iomem).

/proc/stat Allgemeine Informationen über den Status der Prozessoren. Diese Informationen werden vom Programm procinfo verwendet und übersichtlich aufgelistet.

/proc/uptime Anzahl der Sekunden, seitdem das System gestartet ist, und wie lange davon die CPU mit dem Nichtstun (HLT) (Leerlaufzeit = engl. idle) verbracht hat

/proc/scsi/ Unterverzeichnis mit Informationen zu SCSI-Geräten

/proc/scsi/scsi Sofern Sie eine SCSI-Schnittstelle besitzten, finden Sie hier eine Auflistung aller Geräte.

/proc/ide/ Unterverzeichnis mit Informationen zu IDE-Geräten

/proc/apm Informationen zum Advanced Power Management (z. B. ein Text wie »AC off-line« bedeutet, dass ein Notebook im Batteriebetrieb läuft)

/proc/mounts Liste aller »gemounteten« Dateisysteme

/proc/net/ Unterverzeichnis zu Netzwerkinformationen

/proc/loadavg Duchschnittliche Systemauslastung (eine Minute, drei Minuten, fünf Minuten, aktive Prozesse/Anzahl Prozesse, und zuletzt benutzte PID)

Verzeichniseintrag Bedeutung

Tabelle 4.1 Systeminformationen im /proc-Verzeichnis (Forts.)

Page 26: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

134

4

char buffer[BUF];size_t bytes_read;

if((fp = fopen(info[inf], "r")) == NULL) {perror("fopen()");return;

}bytes_read = fread (buffer, 1, sizeof (buffer), fp);fclose (fp);if (bytes_read == 0 || bytes_read == sizeof (buffer))

return;buffer[bytes_read] = '\0';

printf("%s",buffer);printf("Weiter mit ENTER");getchar();return;

}

int main (void) {int auswahl;do {

printf("Wozu benötigen Sie Informationen?\n\n");printf("-%d- Prozessor\n", CPU);printf("-%d- Geräte\n", DEV);printf("-%d- DMA\n", DMA);printf("-%d- Interrupts\n", INT);printf("-%d- I/O-Ports\n", IOP);printf("-%d- Speicher\n", MEM);printf("-%d- Version\n", VERS);printf("-%d- SCSI\n", SCSI);printf("-%d- Programmende\n", EXIT);printf("\nIhre Auswahl : ");do{ scanf("%d",&auswahl); } while(getchar() != '\n');

switch(auswahl) {case CPU : get_info(CPU); break;case DEV : get_info(DEV); break;case DMA : get_info(DMA); break;case INT : get_info(INT); break;case IOP : get_info(IOP); break;case MEM : get_info(MEM); break;case VERS: get_info(VERS); break;case SCSI: get_info(SCSI); break;case EXIT: printf("Bye\n"); break;default : printf("Falsche Eingabe?\n");

}} while(auswahl != EXIT);return EXIT_SUCCESS;

}

Page 27: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Prozessinformationen 4.3

135

Das Programm im Einsatz:

$ ./myinfoWozu benötigen Sie Informationen?

-0- Prozessor-1- Geräte-2- DMA-3- Interrupts-4- I/O-Ports-5- Speicher-6- Version-7- SCSI-8- Programmende

Ihre Auswahl : 7Attached devices:Host: scsi0 Channel: 00 Id: 00 Lun: 00Vendor: VMware, Model: VMware Virtual S Rev: 1.0Type: Direct-Access ANSI SCSI revision: 02

Host: scsi2 Channel: 00 Id: 00 Lun: 00Vendor: MATSHITA Model: DVD-RAM UJ-850S Rev: 1.60Type: CD-ROM ANSI SCSI revision: 05

Weiter mit ENTER

4.3 Prozessinformationen

Neben Hardware-Informationen können Sie aus dem /proc-Filesystem auch Informationen zuden einzelnen Prozessen ermitteln. Auch Programme wie ps oder top nutzen diese Möglich-keit, um Ihnen Informationen zu einem Prozess zu liefern. Den Prozessen und deren Verwal-tung ist extra noch ein Kapitel gewidmet. Das /proc-Filesystem beinhaltet für jeden Prozessextra ein Unterverzeichnis. Der Name des Verzeichnisses entspricht der Prozess-ID. Lassen Siesich am besten das /proc-Verzeichnis ausgeben:

$ ls -l /proc | lessdr-xr-xr-x 3 root root 0 2003-11-13 23:46 1dr-xr-xr-x 3 root root 0 2003-11-13 23:46 12dr-xr-xr-x 3 root root 0 2003-11-13 23:46 1201dr-xr-xr-x 3 root root 0 2003-11-13 23:46 1278dr-xr-xr-x 3 bin root 0 2003-11-13 23:46 1303...dr-xr-xr-x 4 root root 0 2003-11-13 23:47 tty-r--r--r-- 1 root root 0 2003-11-13 23:47 uptime

Hinweis

Fragen zum Löschen des Bildschirms in einem Terminal werden in Kapitel 13, »Terminal E/A undBenutzerschnittstellen für die Konsole«, beantwortet.

Page 28: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

136

4

-r--r--r-- 1 root root 0 2003-11-13 23:47 versiondr-xr-xr-x 3 root root 0 2003-11-13 23:47 video

Diese Verzeichnisse werden als Prozessverzeichnisse bezeichnet, da sich diese auf die Prozess-ID (PID) beziehen (komischerweise taucht es in den 2.6er-Sources als »TGID« auf ...) und Infor-mationen zu diesem Prozess beinhalten. Eigentümer und Gruppe eines jeden solchen PID-Verzeichnisses werden auf die ID des Benutzers, der den Prozess ausführt, gesetzt. (Eine nach-trägliche Änderung über setuid() ändert nur den Eigentümer des Verzeichnisses, nicht dender Dateien.) Nach Beendigung des Prozesses wird der Eintrag im /proc-Verzeichnis ebenfallswieder gelöscht. Während der Ausführung eines Prozesses können Sie aus dem Verzeichnisdie nun folgenden nützlichen Informationen dazu erhalten:

#include <unistd.h.>int main(void) { setuid(25); while(1); }

Im Hintergrund ausführen (»./a.out &«) und reingucken:

# ./a.out &[1] 2275# ls -l /proc/2275/insgesamt 0-r--r--r-- 1 tot users 0 2004-08-14 02:36 cmdline-r-------- 1 tot users 0 2004-08-14 02:36 environlrwxrwxrwx 1 tot users 0 2004-08-14 02:36 exe->./a.outdr-x------ 2 tot users 0 2004-08-14 02:36fd-rw------ 1 tot users 0 2004-08-14 02:36 mapped_base-r--r--r-- 1 tot users 0 2004-08-14 02:36 maps-rw------- 1 tot users 0 2004-08-14 02:36 mem-r--r--r-- 1 tot users 0 2004-08-14 02:36 mountslrwxrwxrwx 1 tot users 0 2004-08-14 02:36 root -> /

-r--r--r-- 1 tot users 0 2004-08-14 02:36 stat-r--r--r-- 1 tot users 0 2004-08-14 02:36 statm-r--r--r-- 1 tot users 0 2004-08-14 02:36 status

Gilt auch für seteuid() und setreuid().

4.3.1 /proc/$pid/cmdline

Sie finden z. B. ein Verzeichnis mit der ID 2167 und wollen wissen, was in der Kommando-zeile des Prozesses steht, dann müssen Sie nur cmdline abfragen:

$ cat /proc/2167/cmdlineanjuta

Der Prozess mit der ID 2167 ist also das Programm (die Entwicklungsumgebung) Anjuta beider Ausführung. Wollen Sie alle Prozesse ausgeben lassen, können Sie dies auch folgenderma-ßen machen:

# cat /proc/[0-9]*/cmdline

Da die Ausgabe allerdings zu wünschen übrig lässt, sollten Sie hierfür das Kommando stringseinsetzen:

Page 29: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Prozessinformationen 4.3

137

# strings -f /proc/[0-9]*/cmdline

Und schon bekommen Sie alle zu den Prozess-IDs gehörenden Namen ausgegeben. Mit cmd-line können Sie eine einzelne Zeile des Prozesses ausgeben, worin der Name (oder auch dasKommando) des Programms mit allen Argumenten enthalten ist.

Falls strings bei Ihnen nicht machen will, was es soll, können Sie auch folgende Eingabe ver-wenden:

# grep -Ha "" /proc/[0-9]*/cmdline | tr '\0' " "

4.3.2 /proc/$pid/environ

Jeder Prozess hat außerdem auch eine Prozessumgebung. Welche Umgebungsvariablen fürwelchen Prozess gesetzt sind, können Sie mit environ im /proc-Verzeichnis der Prozess-IDerfragen. Hier soll weiterhin der Prozess mit der ID 2167, die EntwicklungsumgebungAnjuta, beobachtet werden:

$ strings -f /proc/2167/environ/proc/2167/environ: LESSKEY=/etc/lesskey.bin/proc/2167/environ:MANPATH=/usr/local/man:/usr/share/man:/../proc/2167/environ:INFODIR=/usr/local/info:/usr/share/.../proc/2167/environ: NNTPSERVER=news.../proc/2167/environ: KDE_FULL_SESSION=true/proc/2167/environ: KDE_MULTIHEAD=false/proc/2167/environ: SESSION_MANAGER=local/linux:/tmp/.IC.../proc/2167/environ: KDE_STARTUP_ENV=linux;1068759934;528706;1890

Wenn es auch hier wieder nicht mit strings klappen sollte, dann sollten Sie es mit Folgendemprobieren:

# tr '\0' '\n' < /proc/2167/environ

4.3.3 /proc/self

Wollen Sie die aktuelle Prozess-ID Ihres eigenen Programms ermitteln, so können Sie /proc/self auswerten. Bei diesem Eintrag handelt es sich um einen symbolischen Link des aktuelllaufenden Prozesses. Das aktuelle Programm sollten Sie aber nicht mit der Shell verwechseln(versuchen Sie selbst: ls -dl /proc/self und ls -dl /proc/$$). Diesen symbolischen Linkkönnen Sie mit der Funktion readlink() auslesen. Hier ein Listing, das demonstriert, wie Siedie Prozess-ID des aktuell laufenden Programms ermitteln können:

/* my_getpid.c */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <unistd.h>

int main (void) {

Page 30: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

138

4

char buf[64];int pid;

memset(buf, '\0', sizeof(buf));readlink("/proc/self", buf, sizeof(buf) - 1);sscanf(buf, "%d", &pid);printf("Meine Prozess-ID lautet: %d\n", pid);return EXIT_SUCCESS;

}

Das Programm bei seiner Ausführung:

$ gcc -o my_getpid my_getpid.c$ ./my_getpidMeine Prozess-ID lautet: 2256

4.3.4 /proc/$pid/fd/

Ein weiterer Eintrag ist fd, ein Unterverzeichnis, das alle Einträge von Filedeskiptoren bein-haltet, die ein Prozess geöffnet hat. Jeder Eintrag darin ist ein symbolischer Link, der auf einebestimmte Datei lesend oder schreibend zurückgreift. Natürlich sind hierbei auch immer dieStandard-Filedeskriptoren (0, 1, 2) enthalten (es sei denn, sie wurden geschlossen, was vieleDämonen etc. tun!). Öffnen Sie eine Konsole, und geben Sie ps ein:

$ psPID TTY TIME CMD1988 pts/1 00:00:00 bash2827 pts/1 00:00:00 ps

Wollen Sie jetzt wissen, welche Filedeskiptoren bash offen hat, machen Sie Folgendes:

$ ls -l /proc/1988/fd/insgesamt 0lrwx------ 1 tot users 64 2003-11-14 00:50 0->/dev/pts/1lrwx------ 1 tot users 64 2003-11-14 00:50 1->/dev/pts/1lrwx------ 1 tot users 64 2003-11-14 00:50 2->/dev/pts/1

Hierbei können Sie die drei Standard-Filedeskriptoren als symbolischen Link auf dem Pseudo-Terminal pts/1 wieder erkennen. Sie können jetzt ohne weiteres auf diese Filedeskriptorenzugreifen:

$ echo "Ein Beweis gefällig?" > /proc/1988/fd/1Ein Beweis gefällig?

Hier wurde die Standardausgabe von echo auf die eigentliche Standardausgabe des Pseudo-Terminals »geleitet«.

Hinweis

Das Beispiel stellt natürlich nur eine Demonstration dar. In der Praxis werden Sie auf die Funktiongetpid() für die Ermittlung der Prozess-ID des laufenden Programms zurückgreifen.

Page 31: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Kernel-Informationen 4.4

139

4.3.5 /proc/$pid/statm

Informationen zur Speicherbelegung eines Prozesses werden im statm-File hinterlegt. WollenSie z. B. die Speicherbelegung der Entwicklungsumgebung Anjuta ermitteln, gehen Sie fol-gendermaßen vor:

$ cat /proc/2167/statm2671 2670 1678 302 0 2368 992

Sie bekommen dabei sieben verschiedene Zahlen zurück. Hier die Bedeutung der einzelnenZahlen von links nach rechts:

� Gesamte Programmgröße in Kilobyte

� Größe von Speicherteilen in Kilobyte

� Anzahl von »geshareten« Seiten (so genannte Pages)

� Anzahl Seiten von Programmcode

� Anzahl Seiten von Stack/Daten

� Anzahl Seiten von Bibliotheksprogrammcode

� Anzahl von unsauberen Seiten

Es gibt noch weitere nützliche Informationen zu den Prozessen, die Sie jetzt in der folgendenTabellen aufgelistet finden. $pid ersetzen Sie bitte für eine echte Prozess-ID.

4.4 Kernel-Informationen

Viele Einträge im /proc-Verzeichnis geben auch Informationen zum laufenden Kernel aus.Der Ort der Kernel-Informationen ist unterschiedlich, viele liegen im /proc-Verzeichnis selbstund weitere in den Unterverzeichnissen wie /proc/sys oder /proc/sys/kernel.

Verzeichniseintrag Bedeutung

/proc/$pid/status Darin finden Sie die formatierten Informationen, die Sie ebenfalls mit /proc/$pid/stat (allerdings nicht formatiert) ermitteln können. Dies sind Informatio-nen wie die Prozess-ID, die reale und effektive User- und Group-ID, Speicher-verbrauch, Bitmasken usw.

/proc/$pid/stat Siehe /proc/$pid/status.Dies ist eine etwas kompaktere Datei, die sich besser als »status« mit sscanf() oder fscanf() verwenden lässt.

/proc/$pid/cwd Ein symbolischer Link zum aktuellen Arbeitsverzeichnis des Prozesses

/proc/$pid/exe Ein Verweis auf die ausführbare Programmdatei

/proc/$pid/root Ein Link zum Root-Verzeichnis, das als Wurzelverzeichnis für den Prozess gilt (siehe chroot())

/proc/$pid/maps Beinhaltet Speicher-Mappings zu den verschiedenen laufenden Dateien und Bibliotheken, die mit diesem Prozess zusammenhängen. Die Datei kann sehr lang werden, wenn ein umfangreicher Prozess ausgeführt wird.

Tabelle 4.2 Prozessinformationen in den individuellen PID-Verzeichnissen

Page 32: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

140

4

Hierzu einige häufig benötigte Informationen, die in viele Anwendungen integriert sind:

$ cat /proc/sys/kernel/ostypeLinux$ cat /proc/sys/kernel/osrelease2.6.27-7-generic$ cat /proc/sys/kernel/version#1 SMP Tue Jan 4 19:33:20 UTC 2009$ cat /proc/sys/kernel/ctrl-alt-del0

Zuerst wurde abgefragt, was für ein Betriebssystem genau hier läuft (ostype), dann die Ver-sion des Kernels (osrelease) und wann dieser Kernel kompiliert wurde (version). Bei derletzten Abfrage wird überprüft, ob ctrl-alt-del gesetzt ist. Damit können Sie beeinflussen,ob init bei der Tastenkombination (Ctrl)+(Alt)+(Del) eine Aktion ausführen soll. Steht»ctrl-alt-del« auf 1, wird bei Tastendruck sofort ein BIOS-Reboot angeordnet. Steht »ctrl-alt-del« allerdings auf 0, wird init dazu angehalten, das System ordentlich herunterzufahrenWollen Sie diesen Parameter verändern, müssen Sie sich schnell als Superuser darstellen:

$ suPassword:********# echo 1 >> /proc/sys/kernel/ctrl-alt-del# exitexit$ cat /proc/sys/kernel/ctrl-alt-del1

Ein weiteres Beispiel. Sie haben eine CD-ROM eingelegt und gemountet. Nachdem Sie dieDaten von der CD-ROM gelesen haben, werfen Sie die CD-ROM ordnungsgemäß mit umountwieder aus und fahren anschließend das System herunter. Jetzt benötigen Sie aber die CD-ROM für einen Bekannten. Somit müssen Sie den PC leider nochmals anschalten. Wäre dochnett, wenn beim Ausgeben der CD-ROM die CD ausgeworfen wird. Für solche Fälle ist derEintrag in /proc/sys/dev/cdrom/autoeject zuständig. Der Wert ist mit der Voreinstellung 0versehen. Folgendermaßen können Sie dabei vorgehen, um den Wert auf 1 zu setzen:

$ mount /media/cdrom$ cat /proc/sys/dev/cdrom/autoeject0$ suPassword:********# echo 1 >> /proc/sys/dev/cdrom/autoeject# exitexit$ cat /proc/sys/dev/cdrom/autoeject1$ umount /media/cdrom

Beim Aushängen des CD-ROM-Laufwerkes müsste jetzt die CD ausgeworfen werden. Diesesnette Feature zeigt allerdings schon recht früh seine Schattenseiten, z. B. wenn die Hard-wareerkennung oder das Installationsprogramm das Device mehrmals öffnet und schließt.

Page 33: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Kernel-Informationen 4.4

141

Besonders fies auf engem Raum, wo Ihr CD-Laufwerk leiden wird, wenn es sich nicht vollstän-dig öffnen kann.

Sie hacken übrigens damit nicht im System herum. Viele dieser Kernel-Parameter wurdenbewusst so implementiert, damit Sie den Bedürfnissen der Anwender angepasst werden kön-nen, um ein höchstes Maß an Flexibilität zu erreichen. Da dabei in der Regel Superuser-Rechtebenötigt werden, sind diese Einstellungen meistens für den Systemadministrator vorgesehen.Daher macht es relativ wenig Sinn, wenn Sie in Ihrer Anwendung, die Sie schreiben, versu-chen, die Kernel-Parameter zu verändern. Dies würde bedeuten, dass Ihre Anwendung imSuperuser-Modus laufen müsste. Bedenken Sie, dass dies nicht immer möglich ist – und auchnicht sein sollte.

Für administrative Zwecke soll hierfür jedoch eine solche Anwendung erstellt werden. Aberwie schon erwähnt, Sie benötigen Superuser- Rechte (bzw. root-Rechte) für dieses Programm,sollten Sie etwas verändern wollen. Versucht der normale Anwender, etwas zu verändern,bekommt er ein »Permission denied« zurückgegeben. Hier das Beispiel mit anschließenderErläuterung.

/* kernelinf.c */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h.>#include <string.h>#define BUF 4096

enum { EJECT, FILE_MAX, SHARED_MAX };enum { CDINFO, OS, RELEASE, VERSION };

static const char *sys[] = {/* Bei umount CD auswerfen */"/proc/sys/dev/cdrom/autoeject",/* max. Anzahl geöffneter Dateien pro Prozess */"/proc/sys/fs/file-max",/*max. Größe geteilter Speicher (Shared Memory) */"/proc/sys/kernel/shmmax"

};

static const char *info[] = {"/proc/sys/dev/cdrom/info", /* Infos zur CD-ROM */"/proc/sys/kernel/ostype", /* Welches Betriebssystem */"/proc/sys/kernel/osrelease" /* Kernel-Version */"/proc/sys/kernel/version" /* Kernel von wann */

};

static char *get_info (const char *inf) {FILE *fp;static char buffer[BUF];

Page 34: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

142

4

size_t bytes_read;

fp = fopen (inf, "r");if (fp == NULL) {perror("fopen()");return NULL; /* Fehler beim Öffnen */

}bytes_read = fread (buffer, 1, sizeof (buffer), fp);fclose (fp);if (bytes_read == 0 || bytes_read == sizeof (buffer))return NULL;

buffer[bytes_read] = '\0';return buffer;

}

static void set_sys (const char *sys, unsigned long set) {FILE *fp;char buf[32];

fp = fopen (sys, "w");if (fp == NULL) {perror ("fopen()");printf ("Weiter mit ENTER\n");getchar ();return;

}sprintf(buf, "%ld", set);fprintf (fp, "%s", buf);fclose (fp);return;

}

int main (int argc, char **argv) {int auswahl;unsigned int file_max;unsigned long shared_max;

do {printf ("Aktueller Zustand\n");printf ("Betriebssystem : %s", get_info (info[OS]));printf ("Kernel-Version : %s",

get_info (info[RELEASE]));printf ("Datum : %s",

get_info (info[VERSION]));printf ("------------------------------------\n");printf ("Verändern können Sie Folgendes ...\n");printf ("-0- Bei \"umount\" CD auswerfen"

" Aktuell:%s", get_info (sys[EJECT]));printf ("-1- Max. Anzahl geöffneter Dateien pro"

Page 35: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Kernel-Informationen 4.4

143

" Prozess Aktuell:%s",get_info (sys[FILE_MAX]));

printf ("-2- Max. Größe des geteilten Speichers"" (KB) Aktuell %s",

get_info (sys[SHARED_MAX]));printf ("------------------------------------\n");printf ("Informationen bekommen Sie zu ...\n");printf ("-3- CD-ROM\n");printf ("------------------------------------\n");printf ("-4- ENDE\n");printf ("Ihre Auswahl bitte (0-4) : ");

do { scanf ("%d", &auswahl); } while (getchar ()!='\n');switch (auswahl) {case EJECT:

if (strncmp ("0", get_info (sys[EJECT]),1) == 0)set_sys (sys[EJECT], 1); /* Setzen */

else /* Zurücksetzen */set_sys (sys[EJECT], 0);

break;case FILE_MAX:

printf ("Welcher Wert soll gesetzt werden : ");do{ scanf("%d", &file_max); } while (getchar()!='\n');set_sys (sys[FILE_MAX], file_max);break;

case SHARED_MAX:printf ("Welcher Wert soll gesetzt werden : ");do { scanf("%ld", &shared_max); }while (getchar()!='\n');set_sys (sys[SHARED_MAX], shared_max);break;

case 3:printf ("%s", get_info (info[CDINFO]));printf ("Weiter mit ENTER\n");getchar ();break;

case 4:printf("Programm wird beendet\n");break;

default:printf ("Unbekannte Eingabe\n");

}} while (auswahl != 4);return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o kernelinf kernelinf.c$ ./kernelinfAktueller Zustand

Page 36: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

144

4

Betriebssystem : LinuxKernelversion : 2.6.27-7-genericDatum : #1 SMP Tue Jan 4 19:33:20 UTC 2009------------------------------------Verändern können Sie folgendes ...-0- Bei "umount" CD auswerfen Aktuell:0-1- Max. Anzahl geöffneter Datei pro Prozess Aktuell:49594-2- Max. Größe des geteiltem Speicher (KB) Aktuell 33554432------------------------------------Informationen bekommen Sie zu ...-3- CD-ROM-------------------------------------4- ENDEIhre Auswahl bitte (0-4) :

Neben dem Auswerfen der CD-ROM bei umount können hier noch die maximale Anzahlgleichzeitig geöffneter Dateien pro Prozess und die maximale Größe des geteilten Speichers(Shared Memory) verändert werden. Diese Veränderungen können aber wie bereits erwähntnur mit speziellen Rechten vorgenommen werden. Informationen zum CD-ROM-Laufwerk,was es alles kann, können wieder für alle Anwender aufgelistet werden.

Bitte beachten Sie, dass diese Art von Veränderungen der Kernel-Parameter nur für den lau-fenden Betrieb gültig ist. Sobald Sie das System herunterfahren und wieder starten, sind dieWerte wieder auf ihren Ursprungszustand gestellt. Wollen Sie eine dauerhafte Veränderungbewirken, müssen Sie sich die Datei sysctl.conf im Verzeichnis /etc vornehmen. DieseDatei können Sie auch mit dem gleichnamigen Kommando sysctl verändern. Wollen Sie z. B.mit sysctl autoeject verändern, gehen Sie wie folgt vor (root-Rechte):

# sysctl -w dev.cdrom.autoeject=0dev.cdrom.autoeject = 0# sysctl -w dev.cdrom.autoeject=1dev.cdrom.autoeject = 1

Auf die Angaben von /proc/sys können Sie dabei verzichten, und anstelle eines Slashs wirdein Punkt verwendet.

Wollen Sie wissen, mit welchem Befehl der Kernel beim Booten gestartet wurde, können Sieihn mit cmdline erfragen:

$ cat /proc/cmdlineroot=/dev/hda6 vga=0x0314 hdc=ide-scsi hdclun=0 splash=silent

Oder Linux 2.6 mit LILO 22.3.4:

auto BOOT_IMAGE=2.6.4-HX ro root=301

Zu den verschiedenen Bootoptionen sei hier der Verweis auf die bootparam(7) Manual Pagegegeben. Es gibt noch weitaus mehr zu den Kernel-Informationen zu sagen, aber das würdeden Rahmen des Buches bei weitem sprengen und am Thema der Linux-Programmierung vor-beigehen.

Page 37: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Kernel-Informationen 4.4

145

4.4.1 /proc/locks

Mit dieser Datei werden alle Dateien angezeigt, die im Augenblick vom Kernel gesperrt wer-den (vgl. Kapitel 2 über flock() und lockf()). Diese Ausgabe enthält interne Kernel-Debug-ging-Daten und kann daher logischerweise je nach System stark variieren.

1: FLOCK ADVISORY WRITE 807 03:05:308731 0 EOF c2ac0 c0248 c2a2202: POSIX ADVISORY WRITE 708 03:05:308720 0 EOF c2a1c c2ac4 c02548

In der ersten Spalte besitzt jeder Lock eine einmalige Zahl gefolgt vom Typ des Locks. Mögli-che Ausgaben sind hier FLOCK (meist bei älteren UNIX-Datei-Locks mit dem Systemaufrufflock()) und POSIX (bei neueren POSIX-Locks mit dem Systemaufruf lockf()).

Der Wert ADVISORY der dritten Spalte bedeutet, dass ein weiterer Datenzugriff für andereBenutzer möglich ist, aber keine weiteren Lock-Versuche mehr erlaubt sind. Ein anderer Werthierfür wäre MANDATORY, was bedeutet, dass hier keine Datenzugriffe mehr möglich sind,solange der Lock vorhanden ist. In der vierten Spalte befinden sich die Lese- oder Schreib-rechte (READ, WRITE) des Eigentümers. Die fünfte Spalte enthält die PID des Lock-Eigentü-mers. Die ID der gelockten Datei finden Sie in der sechsten Spalte mit folgendem Format:

MAJOR-DEVICE:MINOR-DEVICE:INODE-NUMBER

Die Spalten sechs und sieben zeigen Anfang und Ende der gelockten Region. Im Beispiel giltdie Sperre vom Anfang 0 bis zum Ende (EOF) der Datei. Die letzten Spalten zeigen auf Kernel-interne Datenstrukturen für spezielle Debugging-Funktionen.

4.4.2 /proc/modules

In /proc/modules finden Sie eine Liste von allen Modulen, die vom System geladen wurden.Auch hierbei hängt die Ausgabe von den Einstellungen des Systems ab.

$ cat /proc/modulesisofs 40100 1 - Live 0xe0c36000udf 88356 0 - Live 0xe0c94000crc_itu_t 10112 1 udf, Live 0xe0bff000btusb 19736 0 - Live 0xe0c23000nls_iso8859_1 12032 1 - Live 0xe0c1f000nls_cp437 13696 1 - Live 0xe0c09000vfat 18816 1 - Live 0xe0c03000fat 57376 1 vfat, Live 0xe0c0f000ipv6 263972 15 - Live 0xe0c52000........

In der ersten Spalte befindet sich jeweils der Name des geladenen Moduls, gefolgt von derSpeichergröße in Bytes. In der dritten Spalte wird angezeigt, wie oft das Modul gerade benutztwird (usage count). In der letzten Spalte finden Sie die Module, die benötigt werden, damitandere Module funktionieren. Zum Beispiel benötigt das Modul cdrom das Modul ide-cd, umordentlich ausgeführt zu werden. »autoclean« gibt an, ob sich das Modul nach einer gewissenZeit selbst deaktiviert, »unused«, dass es nicht benutzt wird.

Page 38: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zugriff auf Systeminformationen

146

4

4.5 Filesysteme

Weitere Informationen, die Sie im /proc-Verzeichnis finden, sind die über verschiedene File-systeme und welche dabei eingehängt (»gemountet«) sind. Das Verzeichnis /proc/filesys-tems z. B. listet alle Filesysteme auf, die dem Kernel bekannt sind und womit dieser arbeitenkann. Einige davon sind intern und können nicht gemountet werden, auch wenn sie hier auf-gelistet werden. Dazu zählt z. B. pipefs; wobei diese Auflistung nicht vollständig ist. Denn esgibt noch viele Filesysteme, die nachgeladen werden können und gerade nicht aktiv sind.Andere wiederum sind nur statisch gelinkt und werden erst bei Bedarf aktiviert.

4.5.1 /proc/mounts

Was alles gerade eingehängt ist, finden Sie in /proc/mounts verzeichnet, z. B.:

rootfs / rootfs rw 0 0/dev/root / reiserfs rw 0 0proc /proc proc rw 0 0sysfs /sys sysfs rw 0 0devpts /dev/pts devpts rw 0 0tmpfs /dev/shm tmpfs rw 0 0/dev/hda2 /C vfat rw,nodiratime,fmask=0022,dmask=0022,codepage=cp437 0 0usbdevfs /proc/bus/usb usbdevfs rw 0 0/dev/hdb /F iso9660 ro,nosuid,nodev 0 0

Die Ausgabe von /proc/mount entspricht (fast) exakt der Ausgabe von /etc/mtab, nur dass/etc/mtab von mount verwaltet wird und somit nur Dateisysteme auflistet, die mit /bin/mount eingehängt worden sind, nicht jedoch z. B. der Systemcall mount().

In der ersten Spalte einer jeden Zeile finden Sie das Gerät und in der zweiten Spalte den dazu-gehörenden Mountpoint. Der Dateisystemtyp wird in der dritten Spalte aufgelistet. Ob daraufnur lesend (ro) oder auch schreibend (rw) zugegriffen werden kann, wird – nebst anderenmöglichen Optionen – in der vierten Spalte angezeigt. Die letzten beiden Spalten sindDummy-Werte, damit das /proc/mount-Format exakt dem von /etc/mtab entspricht.

4.6 Weiterführendes

Zum /proc-Verzeichnis könnten noch viele Seiten geschrieben werden, aber irgendwo mussSchluss sein. Sie wissen jetzt, wenn Sie bestimmte Informationen für Ihr Programm oder auchzur Administration benötigen, wo und wie Sie an diese Informationen herankommen. Wei-tere Informationen zum /proc-Verzeichnis finden Sie auf der Manual Page »man 5 proc«.

Dass Linux frei im Quellcode ist (Open Source), weiß – denke ich – schon jeder. Daher hierzueinige Anwendungen, deren Quellcode zu studieren sinnvoll erscheint, da diese kräftigGebrauch vom /proc-Verzeichnis machen.

Page 39: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Weiterführendes 4.6

147

Anwendung Beschreibung

mount Informationen über gemountete Datenträger

ps Informationen über Prozesse

top Auslastung der CPU

xload Durchschnittliche Auslastung des Systems

xosview Durchschnittliche Auslastung des Systems, der CPU, des Speicherbedarf, Interrupts ...

Tabelle 4.3 Anwendungen, die vom /proc-Verzeichnis profitieren

Page 40: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

349

Neben den Prozessen existiert noch eine andere Form der Programmausführung, die Linux unterstützt – die Threads, die auch als »leichtgewichtige« Prozesse bekannt sind.

10 Threads

Mit der Thread-Programmierung können Sie Anwendungen schreiben, die erheblich schnel-ler und parallel ablaufen. Sie erhalten in diesem Kapitel einen Einblick in die Thread-Program-mierung unter Linux und erfahren, wie Sie diese Kenntnisse in der Praxis einsetzen können.

$ gcc -o thserver thserver.c \-I/usr/local/include/pthread/linuxthreads \-L/usr/local/lib -llthread -llgcc_r

10.1 Unterschiede zwischen Threads und Prozessen

Prozesse wurden ja bereits ausführlich erklärt. Sie wissen, wie Sie eigene Prozesse mittelsfork() kreieren können, und mit Interprozesskommunikationen (IPC) haben Sie erfahren,wie man einzelne Prozesse synchronisiert. Den Aufwand, den Sie bei den Interprozesskom-munikationen gemacht haben, entfällt bei den Threads fast komplett.

Ein weiterer Nachteil bei der Erstellung von Prozessen gegenüber Threads ist der enorme Auf-wand, der mit der Duplizierung des Namensraumes gemacht wird – den man mit den Threadsnicht hat, da diese in einem gemeinsamen Adressraum ablaufen. Somit stehen den einzelnenThreads dasselbe Codesegment, Datensegment, der Heap und alle anderen Zustandsdaten, dieein »gewöhnlicher« Prozess besitzt, zur Verfügung – was somit auch die Arbeit beim Aus-tausch von Daten und bei der Kommunikation untereinander erheblich erleichtert. Weil aberkein Speicherschutzmechanismus unter den Threads vorhanden ist, bedeutet dies auch, wennein Thread abstürzt, reißt dieser alle anderen Threads mit.

Im ersten Moment besteht somit vorerst gar kein Unterschied zwischen einem Prozess undeinem Thread, denn letztendlich besteht ein Prozess mindestens aus einem Thread. Ferner

Hinweis

Die Beispiele im Buch verwenden Linux-Threads und sind somit nicht ohne weiteres auf anderenUNIXen lauffähig. Die BSD-Threads z. B. arbeiten zum Teil ähnlich. Es kann aber sein, dass das eineProgramm läuft und ein anderes nicht und daher auf die Linux-Threads verlinkt werden muss. Voraus-setzung sind also Linux-Threads. Speziell unter (Free)BSD müssen Sie die Linux-Threads aus den Portsinstallieren und das Programm folgendermaßen übersetzen:

Page 41: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

350

10

endet ein Prozess, wenn sich alle Threads beenden. Somit ist der EINE Prozess (dieser eineProzess ist der erste Thread, auch »Main Thread« bzw. »Haupt-Thread« genannt) verantwort-lich für die gleichzeitige Ausführung mehrerer Threads – da doch Threads auch nur innerhalbeines Prozesses ausgeführt werden. Der gravierende Unterschied zwischen den Threads undden Prozessen besteht darin, dass Threads unabhängige Befehlsfolgen innerhalb eines Prozes-ses sind. Man könnte auch sagen, Threads sind in einem Prozess gefangen oder verkapselt –im goldenen Käfig eingeschlossen.

Natürlich müssen Sie dabei immer im Auge behalten, wenn Threads denselben Adressraumverwenden, dass sich alle Threads den statischen Speicher und somit auch die globalenVariablen miteinander teilen. Ebenso sieht dies mit den geöffneten Dateien (z. B. Filedeskrip-toren), Signalhandler- und Einstellungen, Benutzer- und Gruppenkennung und dem Arbeits-verzeichnis aus. Daher sind auch in der Thread-Programmierung gewisse Synchronisations-mechanismen nötig und auch vorhanden.

10.2 Thread-Bibliotheken

Zwar werden im Buch hier nur die Linux-Threads behandelt, dennoch sollten hier weitereBibliotheken nicht unerwähnt bleiben. Mitte der 90er-Jahre hat die Entwicklung von zahlrei-chen Thread-Bibliotheken begonnen, wobei sich letztendlich die Bibliothek von Xavier Leroyim Jahre 1997 unter dem Namen Pthread-Lib durchgesetzt hat. Diese Bibliothek wurde vonUlrich Drepper in Glibc2 an die Standardbibliothek angebunden und ist somit auf jedemLinux-System vorhanden. Nachdem Linux jetzt endlich für Mehrprozessorsysteme interessantwurde, wurden die Klagen über die Linux-Thread-Bibliothek lauter. Da es immer wieder Pro-bleme mit Signalen, der hierarchischen Beziehung zwischen Threads, der immer noch nichtganz implementierten POSIX-Konformität und noch andere Sorgen gab, war man auf derSuche nach neuen Thread-Bibliotheken.

� Einen interessanten Ansatz bietet die von Ralf S. Engelschall begonnene Bibliothek GNUPth, die bereits seit 1999 als offizielles GNU-Projekt gestartet wurde. Das »Gute« an dieserBibliothek ist, dass sie sich als eine möglichst portable Bibliothek für nicht präemptivesMultitasking eignet.

� Programmierer von Intel und IBM habe GNU Pth anschließend als Einstiegspunkt verwen-det, um daraus die Next Generation Posix Thread (NGPT) zu entwickeln, die vor allem dieSkalierung auf Mehrprozessorsysteme erhöhen sollte.

� Als Dritte im Bunde kann man die Bibliothek von Red Hat mit Native Posix Thread Libraryhervorheben, die gar eine Veränderung des Kernels nötig machte. Dabei wurden u. a. neueSystemaufrufe, ein erweiterter clone()-Aufruf und vor allem ein funktionierendes Signal-handling eingebaut.

Es sind zwar noch weitere Bibliotheken zu den Threads in der Entwicklung, aber diese hierscheinen mir am interessantesten. Da einige dieser Thread-Bibliotheken noch recht neu sindund da es immer noch ein wenig an Dokumentation dazu fehlt, macht es relativ wenig Sinn,Ihnen diese hier zu demonstrieren. Daher soll hier auf die altbewährte Linux-Thread-Biblio-thek zurückgegriffen werden.

Page 42: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Kernel- und User-Threads 10.3

351

10.3 Kernel- und User-Threads

Es gibt zwei Implementierungen von Threads, zum einen die Kernel-Threads, zum anderendie User-Threads. Die User-Threads sind in einer Bibliothek implementiert, die im Speicher-bereich des Benutzers ablaufen. Damit ist es möglich, Threads auch auf Betriebssystemen zuverwenden, die keine Threads unterstützen. Der Nachteil an den User-Threads ist aber, dassdie einzelnen Threads eines Prozesses nicht auf unterschiedlichen Prozessoren bei Multipro-zessorrechnern laufen. Kernel-Threads hingegen sind bereits im Betriebssystem integrierteThread-Unterstützungen. Dabei wird das Scheduling des Betriebssystems verwendet. So ist esmöglich, die einzelnen Threads eines Prozesses auf verschiedenen Prozessoren laufen zu las-sen. Linux-Threads, die in diesem Kapitel verwendet werden, unterstützen sowohl Kernel- alsauch User-Threads.

Ein wenig überraschend ist es doch, dass die User-Theads, sofern man nicht an die Multipro-zessorprogrammierung appelliert, einen gewissen Vorteil gegenüber der Kernel-Implementie-rung besitzen. Threads, die vom Kernel verwendet werden, setzen doch einige Grenzen, etwawas die Anzahl der gleichzeitigen Benutzer angeht. Aber noch ein wenig überraschender ist,dass User-Threads effizienter als Kernel-Threads ablaufen, da diese keinen extra Befehl (Soft-ware-Interrupt) zum Umschalten auf einen anderen Thread vom Kernel benötigen.

10.4 Scheduling und Zustände von Threads

Auch bei der Thread-Programmierung ist (wie bei den Prozessen) ein Scheduler entweder inder Thread-Bibliothek oder dem Betriebssystem vorhanden, der bestimmt, wann welcherThread Prozessorzeit erhält. Auch hier kann die Zuteilung wie schon bei den Prozessen prio-ritäts- und zeitgesteuert erfolgen. Bei zeitgesteuerten Threads bedeutet dies, dass jedemThread eine bestimmte Zeit (des Prozessors oder der Prozessoren) zur Verfügung steht, ehedieser automatisch unterbrochen wird und anschließend ein anderer Thread an der Reihe ist.Sind die Threads prioritätsgesteuert, so erhält der Thread mit der höchsten Priorität vom Sche-duler den Zuschlag. Außerdem wird ein laufender Thread abgebrochen, wenn ein Thread miteiner höheren Priorität ausgeführt wird. Bitte beachten Sie außerdem, wenn Sie das rein pri-oritätsgesteuerte Scheduling für die Thread-Programmierung verwenden, dass ein Thread mithöchster Priorität den Prozessor für eine uneingeschränkte Zeit verwenden und somit alleanderen Threads von der Arbeit ausschließen kann.

Bei einer User-Level-Thread-Implementierung steht Ihnen nur ein prioritätsgesteuertes Sche-duling zur Verfügung, da ein zeitgesteuertes die Verwendung von Systemcalls erfordert. BeideScheduling-Arten hingegen stehen Ihnen zur Verfügung, wenn die Thread-Bibliothek im Ker-nel des Betriebssystems implementiert wurde.

Anhand der folgenden Abbildung können Sie die Zustände erkennen, in denen sich einThread befinden kann. Bei genauerer Betrachtung fällt auf, dass sich die Threads, abgesehenvon den weiteren Unterzuständen, nicht wesentlich von den Prozessen unterscheiden.

Page 43: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

352

10

� Bereit – Der Thread wartet, bis ihm Prozessorzeit zur Verfügung steht, um seine Arbeit aus-zuführen.

� Ausgeführt – Der Thread wird im Augenblick ausgeführt – bei Multiprozessorsystemenkönnen hierbei mehrere Threads gleichzeitig ausgeführt werden (pro CPU ein Thread).

� Wartet – Der Thread wird im Augenblick blockiert und wartet auf einen bestimmtenZustand (z. B. Bedingungsvariable, Mutex-Freigabe etc).

� Beendet – Ein Thread hat sich beendet oder wurde abgebrochen.

10.5 Die grundlegenden Funktionen zur Thread-Programmierung

10.5.1 pthread_create – einen neuen Thread erzeugen

Einen neuen Thread kann man mit der Funktion pthread_create erzeugen:

#include <pthread.h>

int pthread_create( pthread_t *thread,const pthread_attr_t *attribute,void *(*funktion)(void *),void *argumente );

Wenn Sie sich die Funktion betrachten, dürfte Ihnen die Ähnlichkeit zur Funktion clone()auffallen (siehe Manual Page), worauf sich pthread_create() unter Linux ja auch beruft.Jeder Thread bekommt eine eigene Identifikationsnummer (ID) vom Datentyp pthread_t, diein der Variablen des ersten Parameters thread abgelegt wird. Anhand dieser ID werden alleanderen Threads voneinander unterschieden. Mit dem zweiten Parameter attribute könnenSie bei dem neu zu startenden Thread Attribute setzen wie die Priorität, die Stackgröße undnoch einiges mehr. Auf die einzelnen Attribute wird noch eingegangen. Geben Sie hierfür

Abbildung 10.1 Zustände von Threads

Thread erzeugt Thread bereit

Thread in Ausführung

Thread wird blockiert

Thread wird beendetexited

canceled

Mutex

Conditon Variables

...

Hinweis

Einen Hinweis gleich zu Beginn der Thread-Programmierung – alle Funktionen aus der pthread-Bib-liothek geben bei Erfolg 0, ansonsten bei einem Fehler -1 zurück.

Page 44: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die grundlegenden Funktionen zur Thread-Programmierung 10.5

353

NULL an, werden die Standardattribute für den Thread vorgenommen. Mit dem dritten Para-meter geben Sie die »Funktion« für einen Thread selbst an. Hierbei geben Sie die Anfangs-adresse einer Routine an, die der Thread verwenden soll. Wenn sich die hier angegebeneFunktion beendet, bedeutet dies auch automatisch das Ende des Threads. Argumente, die Siedem Thread mitgeben wollen, können Sie mit dem vierten Parameter argumente übergeben.Meistens wird dieser Parameter verwendet, um Daten an Threads zu übergeben. Hierzu wirdin der Praxis häufig die Adresse einer Strukturvariablen herangezogen.

Nach dem Aufruf von pthread_create() kehrt diese Funktion sofort wieder zurück und fährtmit der Ausführung hinter pthread_create() fort. Der neu erzeugte Thread führt sofort asyn-chron seine Arbeit aus. Jetzt würden praktisch zwei Threads gleichzeitig ausgeführt, derHaupt-Thread und der neue Thread, der vom Haupt-Thread mit pthread_create() erzeugtwurde. Welcher der beiden Threads hierbei zunächst mit seiner Ausführung beginnt, ist nichtfestgelegt (selbes Verhalten wie bei fork).

10.5.2 pthread_exit – einen Thread beenden

Beenden können Sie einen Thread auf unterschiedliche Weise. Meistens werden Threads mitder Funktion pthread_exit() beendet:

#include <pthread.h>

void pthread_exit( void * wert );

Diese Funktion beendet nur den Thread, indem Sie diese aufrufen. Mit dem Argument wertgeben Sie den Exit-Status des Threads an. Diesen Status können Sie mit pthread_join()ermitteln (folgt in Kürze). Natürlich darf auch hierbei, wie eben C-üblich, der Rückgabewertkein lokales Speicherobjekt vom Thread sein, da dieses (wie eben bei Funktionen auch) nachder Beendigung des Threads nicht mehr gültig ist.

Neben der Möglichkeit, einen Thread mit pthread_exit() zu beenden, sind noch folgendeDinge zu beachten:

� Ruft ein beliebiger Thread die Funktion exit() auf, werden alle Threads, einschließlich desHaupt-Threads, beendet (also das komplette Programm). Genauso sieht dies aus, wenn Siedem Prozess das Signal SIGTERM oder SIGKILL senden.

� Ein Thread, der mittels pthread_create() erzeugt wurde, lässt sich auch mit return [wert]beenden. Dies entspricht exakt dem Verhalten von pthread_exit(). Der Rückgabewertkann hierbei ebenfalls mit pthread_join() ermittelt werden.

Exit-Handler für Threads einrichtenWenn Sie einen Thread beenden, können Sie auch einen Exit-Handler einrichten. Dies wirdin der Praxis recht gerne verwendet, um z. B. temporäre Dateien zu löschen, Mutexe freizuge-ben oder eben sonstige »Reinigungsarbeiten« zu machen. Ein solcher eingerichteter Exit-Handler wird dann automatisch bei Beendigung eines Threads mit z. B. pthread_exit() oderreturn automatisch ausgeführt. Das Prinzip ist ähnlich, wie Sie es von der Standardbiblio-theksfunktion atexit() kennen sollten. Auch hierbei werden bei mehreren Exit-Handlern die

Page 45: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

354

10

einzelnen Funktionen in umgekehrter Reihenfolge (da Stack) der Einrichtung ausgeführt. Hierdie Funktionen dazu:

#include <pthread.h>

void pthread_cleanup_push( void (*function)(void *),void *arg );

void pthread_cleanup_pop( int exec );

Eine solche Funktion richten Sie also mit der Funktion pthread_cleanup_push() ein. Als ers-ten Parameter übergeben Sie dabei die Funktion, die ausführt werden soll, und als zweitenParameter die Argumente für den Exit-Handler (falls nötig). Den zuletzt eingerichteten Exit-Handler können Sie wieder mit der Funktion pthread_cleanup_pop() vom Stack entfernen.Geben Sie allerdings einen Wert ungleich 0 als Parameter exec an, so wird diese Funktionzuvor noch ausgeführt, was bei einer Angabe von 0 nicht gemacht wird.

Etwas, was mich hier schon zur Weißglut gebracht hat, ist, dass die beiden Funktionenpthread_cleanup_push() und pthread_cleanup_pop() als Makros implementiert sind. Wasnicht so schlimm wäre, wenn pthread_cleanup_push() eine sich öffnend geschweifte Klam-mer enthält und pthread_cleanup_pop() eine sich schließende. Dies bedeutet, Sie müssenbeide Funktionen im selben Anweisungsblock ausführen. Daher müssen Sie immer ein _pushund ein _pop verwenden, auch wenn Sie wissen, dass eine _pop-Stelle nie erreicht wird.

10.5.3 pthread_join – auf das Ende eines Threads warten

Bevor Sie sich dem ersten Listing widmen können, benötigen Sie noch die Kenntnisse zurFunktion pthread_join().

#include <pthread.h>

int pthread_join( pthread_t thread, void **thread_return );

pthread_join() hält den aufrufenden Thread (meistens den Haupt-Thread), der einen Threadmit pthread_create() erzeugt hat, so lange an, bis der Thread mit der ID thread vom Typpthread_t beendet wurde. Der Exit-Status (bzw. Rückgabewert) des Threads wird an dieAdresse von thread_return geschrieben. Sind Sie nicht am Rückgabewert interessiert, kön-nen Sie hier auch NULL verwenden. pthread_join() ist also das, was Sie bei den Prozessen mitwaitpid() kennen.

Ein Thread, der sich beendet, wird eben so lange nicht »freigegeben« bzw. als beendeterThread anerkannt, bis ein anderer Thread pthread_join() aufruft. Diesen Zusammenhangkönnen Sie bei den Prozessen mit »Zombie-Prozessen« vergleichen. Daher sollte man fürjeden erzeugten Thread einmal pthread_join() aufrufen, es sei denn, man hat einen Thread»abgehängt« (aber dazu in Kürze mehr).

10.5.4 pthread_self – die ID von Threads ermitteln

Die Identifikationsnummer eines auszuführenden Threads können Sie sich mit der Funktionpthread_self() erfragen.

Page 46: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die grundlegenden Funktionen zur Thread-Programmierung 10.5

355

#include <pthread.h>

pthread_t pthread_self(void);

Als Rückgabewert erhalten Sie die Thread-ID vom Datentyp pthread_t.

Hierzu soll nun ein einfaches Beispiel erstellt werden, das alle bisher vorgestellten Funktionenin klarer Weise demonstrieren soll.

/* thread1.c */#include <stdio.h>#include <stdlib.h>#include <pthread.h>/* insg. MAX_THREADS Threads erzeugen */#define MAX_THREADS 3#define BUF 255

/* Einfache Daten für die Wertübergabe an den Thread */struct data {

int wert;char msg[BUF];

};

/* Ein einfacher Exit-Handler für Threads, der ** pthread_cleanup_push und pthread_cleanup_pop ** in der Praxis demonstrieren soll */static void exit_handler_mem( void * arg ) {

printf("\tExit-Handler aufgerufen ...");struct data *mem = (struct data *)arg;/* Speicher freigeben */free(mem);printf("Speicher freigegeben\n");

}

/* Die Thread-Funktion */static void mythread (void *arg) {

struct data *f = (struct data *)arg;/* Exit-Handler einrichten - wird automatisch nach ** pthread_exit oder Thread-Ende aufgerufen */pthread_cleanup_push( exit_handler_mem, (void*)f );/* Daten ausgeben */printf("\t-> Thread mit ID:%ld gestartet\n",

pthread_self());printf("\tDaten empfangen: \n");printf("\t\twert = \"%d\"\n", f->wert);printf("\t\tmsg = \"%s\"\n", f->msg);/* Den Exit-Handler entfernen, aber trotzdem ausführen, ** da als Angabe 1 anstatt 0 verwendet wurde */pthread_cleanup_pop( 1 );/* Thread beenden - Als Rückgabewert Thread-ID verwenden.* Alternativ kann hierfür auch:

Page 47: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

356

10

* return(void) pthread_self();* verwendet werden */

pthread_exit((void *)pthread_self());}

int main (void) {pthread_t th[MAX_THREADS];struct data *f;int i;static int ret[MAX_THREADS];/* Haupt-Thread gestartet */printf("\n-> Main-Thread gestartet (ID:%ld)\n",

pthread_self());/* MAX_THREADS erzeugen */for (i = 0; i < MAX_THREADS; i++) {

/* Speicher für Daten anfordern u. m. Werten belegen*/f = (struct data *)malloc(sizeof(struct data));if(f == NULL) {

printf("Konnte keinen Speicher reservieren ...!\n");exit(EXIT_FAILURE);

}/* Zufallszahl zwischen 1 und 10 (Spezial) */f->wert = 1+(int) (10.0*rand()/(RAND_MAX+1.0));snprintf (f->msg, BUF, "Ich bin Thread Nr. %d", i+1);/* Jetzt Thread erzeugen */if(pthread_create(&th[i], NULL, &mythread, f) != 0) {

fprintf (stderr, "Konnte Thread nicht erzeugen\n");exit (EXIT_FAILURE);

}}/* Auf das Ende der Threads warten */for( i=0; i < MAX_THREADS; i++)

pthread_join(th[i], &ret[i]);/* Rückgabewert der Threads ausgeben */for( i=0; i < MAX_THREADS; i++)

printf("<-Thread %ld ist fertig\n", ret[i]);/* Haupt-Thread ist jetzt auch fertig */printf("<- Main-Thread beendet (ID:%ld)\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread1 thread1.c -lpthread$ ./thread1

-> Main-Thread gestartet (ID:-1209412512)-> Thread mit ID:-1209414736 gestartetDaten empfangen:

wert = "9"

Page 48: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die grundlegenden Funktionen zur Thread-Programmierung 10.5

357

msg = "Ich bin Thread Nr. 1"Exit-Handler aufgerufen ... Speicher freigegeben-> Thread mit ID:-1217807440 gestartetDaten empfangen:

wert = "4"msg = "Ich bin Thread Nr. 2"

Exit-Handler aufgerufen ... Speicher freigegeben-> Thread mit ID:-1226200144 gestartetDaten empfangen:

wert = "8"msg = "Ich bin Thread Nr. 3"

Exit-Handler aufgerufen ...Speicher freigegeben<-Thread –1209414736 ist fertig<-Thread –1217807440 ist fertig<-Thread –1226200144 ist fertig<- Main-Thread beendet (ID:-1209412512)

Dieses Beispiel demonstriert auch auf einfache Weise, wie Sie Daten an einen neu erzeugtenThread übergeben können (hier mit der Struktur data). Ebenfalls gezeigt wurde hier die Ver-wendung eines Exit-Handlers, der nur den im Haupt-Thread angeforderten Speicherbereichfreigibt. Zugegeben, das ließe sich auch im Thread »mythread« einfacher realisieren, aber zuAnschauungszwecken sind solch einfache Codebeispiele immer noch am besten. Im Beispielwurden außerdem drei Threads »mythread« erzeugt, die im Prinzip alle dasselbe machen,nämlich eine einfache Ausgabe der Daten, die an die Threads übergeben wurden. Hierbeimuss nochmals explizit darauf hingewiesen werden, dass die Ausführung, in welcher Reihen-folge die Threads starten, nicht vorgegeben ist, auch wenn dies hier einen anderen Anscheinmacht. Hierzu werden Synchronisationsmechanismen erforderlich. Jeder Thread wurde hiermit pthread_exit() und der eignen Thread-ID als Rückgabewert beendet. Genauso gut kanndies natürlich auch mit return gemacht werden. Der Rückgabewert von den einzelnenThreads wird im Haupt-Thread von pthread_join() erwartet und ausgegeben. Der Haupt-Thread beendet sich am Ende erst, wenn alle Threads fertig sind.

Würden Sie in diesem Beispiel pthread_join() weglassen, so würde sich der Haupt-Threadnoch vor den anderen Threads beenden. Dies bedeutet, dass alle anderen Threads zwar nochlaufen, aber auf nun nicht mehr gültige Strukturvariablen zugreifen würden.

Rückgabewert von ThreadsZwar wurde schon auf den Rückgabewert von Threads eingegangen, aber hierbei wurden nurThread-spezifische Daten zurückgegeben (hier die Thread-ID). Aber genauso wie schon beider Wertübergabe an Threads können Sie hierbei auch ganze Strukturen zurückgeben, was inder Praxis auch häufig so der Fall ist. Hierzu ein ähnliches Beispiel wie schon »thread1.c«, nur

Hinweis am Rand

Bevor sich jemand über die Warnmeldung des Compilers wundert, noch ein Satz zum Casten vonvoid *. In der Programmiersprache C ist ein Casten von oder nach void * nicht nötig. Aber wen dieWarnmeldung stört, der kann dies gerne trotzdem nachholen.

Page 49: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

358

10

dass jetzt die Daten der Struktur aus dem Thread zurückgegeben und im Haupt-Thread mitpthread_join() »abgefangen« und anschließend ausgegeben werden. Auf die Verwendungeines Exit-Handlers wurde der Übersichtlichkeit halber zuliebe verzichtet.

/* thread2.c */#include <stdio.h>#include <stdlib.h>#include <pthread.h>/* insg. MAX_THREADS Threads erzeugen */#define MAX_THREADS 3#define BUF 255

/* Einfache Daten für die Wertübergabe an den Thread */struct data {

int wert;char msg[BUF];

};

/* Die Thread-Funktion */static void *mythread (void *arg) {

struct data *f= (struct data *)arg;/* Zufallszahl zwischen 1 und 10 (Spezial) */f->wert = 1+(int) (10.0*rand()/(RAND_MAX+1.0));snprintf (f->msg, BUF, "Ich bin Thread Nr. %ld",

pthread_self());/* Thread beenden - Als Rückgabewert Strukturdaten* verwenden - Alternativ auch pthread_exit( f ); */

return arg;}

int main (void) {pthread_t th[MAX_THREADS];int i;struct data *ret[MAX_THREADS];

/* Haupt-Thread gestartet */printf("\n-> Main-Thread gestartet (ID:%ld)\n",

pthread_self());/* Speicher reservieren */for (i = 0; i < MAX_THREADS; i++){

ret[i] = (struct data *)malloc(sizeof(struct data));if(ret[i] == NULL) {

printf("Konnte keinen Speicher reservieren ...!\n");exit(EXIT_FAILURE);

}}/* MAX_THREADS erzeugen */for (i = 0; i < MAX_THREADS; i++) {

/* Jetzt Thread erzeugen */if(pthread_create(&th[i],NULL,&mythread,ret[i]) !=0) {

Page 50: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die grundlegenden Funktionen zur Thread-Programmierung 10.5

359

fprintf (stderr, "Konnte Thread nicht erzeugen\n");exit (EXIT_FAILURE);

}}/* Auf das Ende der Threads warten */for( i=0; i < MAX_THREADS; i++)

pthread_join(th[i], (void **)&ret[i]);

/* Daten ausgeben */for( i=0; i < MAX_THREADS; i++) {

printf("Main-Thread: Daten empfangen: \n");printf("\t\twert = \"%d\"\n", ret[i]->wert);printf("\t\tmsg = \"%s\"\n", ret[i]->msg);

}/* Haupt-Thread ist jetzt auch fertig */printf("<- Main-Thread beendet (ID:%ld)\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread2 thread2.c -lpthread$ ./thread2

-> Main-Thread gestartet (ID:-1209412512)Main-Thread: Daten empfangen:

wert = "9"msg = "Ich bin Thread Nr. –1209414736"

Main-Thread: Daten empfangen:wert = "4"msg = "Ich bin Thread Nr. –1217807440"

Main-Thread: Daten empfangen:wert = "8"msg = "Ich bin Thread Nr. –1226200144"

<- Main-Thread beendet (ID:-1209412512)

10.5.5 pthread_equal – die ID von zwei Threads vergleichen

Um einen Thread mit einem anderen Thread zu vergleichen, kann die Funktionpthread_equal() verwendet werden. Dies wird häufig verwendet, um sicherzugehen, dassnicht ein Thread gleich derselbe ist. Ein Wert ungleich 0 wird zurückgegeben, wenn beideThreads gleich sind, und 0 wird zurückgegeben, wenn die Threads eine unterschiedliche Iden-tifikationsnummer (ID) besitzen.

Das folgende Beispiel erzeugt drei Threads mit derselben »Funktion«, hierbei soll jeder Threadwiederum eine andere Aktion ausführen. Im Beispiel ist dies zwar nur die Ausgabe eines Tex-tes, aber in der Praxis könnten Sie hierbei neue Funktionen aufrufen. Für die ersten dreiThreads wird jeweils eine bestimmte Aktion festgelegt. Alle anderen Threads führen nur nochdie else-Aktion aus. Dies ist z. B. sinnvoll, wenn Sie in Ihrer Anwendung Vorbereitungen tref-

Page 51: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

360

10

fen wollen (im Beispiel eben drei Vorbereitungen) so wie Dateien anlegen, Müll beseitigen,eine Server-Verbindung herstellen und noch vieles mehr. Sind diese Vorbereitungen getrof-fen, wird immer mit der gleichen Funktion fortgefahren. Damit der Vergleich von Threadsmit pthread_equal() auch funktioniert, wurden die Thread-IDs, die beim Anlegen mitpthread_create() erzeugt worden sind, in globale Variablen gespeichert – und sind daherauch für alle Threads »sichtbar«. Hier das Beispiel, dessen Ausgabe eigentlich auch einigeserklärt.

/* thread3.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#define MAX_THREADS 5#define BUF 255

/* Globale Variable mit Thread-IDs ** für alle Threads sichtbar */

static pthread_t th[MAX_THREADS];

static void aktion(void *name) {while( 1 ) {

if(pthread_equal(pthread_self(),th[0])) {printf("\t->(%ld): Aufgabe \"abc\" Ausführen \n",

pthread_self());break;

}else if(pthread_equal(pthread_self(),th[1])) {

printf("\t->(%ld): Aufgabe \"efg\" Ausführen \n",pthread_self());

break;}else if(pthread_equal(pthread_self(),th[2])) {

printf("\t->(%ld): Aufgabe \"jkl\" Ausführen \n",pthread_self());

break;}else {

printf("\t->(%ld): Aufgabe \"xyz\" Ausführen \n",pthread_self());

break;}

}pthread_exit((void *)pthread_self());

}

int main (void) {int i;static int ret[MAX_THREADS];

Page 52: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die grundlegenden Funktionen zur Thread-Programmierung 10.5

361

printf("->Haupt-Thread (ID:%ld) gestartet...\n",pthread_self());

/* Threads erzeugen */for (i = 0; i < MAX_THREADS; i++) {

if (pthread_create (&th[i],NULL,&aktion,NULL) != 0) {printf ("Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}}/* Auf die Threads warten */for (i = 0; i < MAX_THREADS; i++)

pthread_join (th[i], &ret[i]);/* Rückgabe der Threads auswerten */for (i = 0; i < MAX_THREADS; i++)

printf("\t<-Thread %ld mit Arbeit fertig\n", ret[i]);printf("->Haupt-Thread (ID:%ld) fertig ...\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread3 thread3.c -lpthread$ ./thread3->Haupt-Thread (ID:-1209412512) gestartet...

->(-1209414736): Aufgabe "abc" Ausführen->(-1217807440): Aufgabe "efg" Ausführen->(-1226200144): Aufgabe "jkl" Ausführen->(-1234592848): Aufgabe "xyz" Ausführen->(-1242985552): Aufgabe "xyz" Ausführen<-Thread -1209414736 mit Arbeit fertig<-Thread -1217807440 mit Arbeit fertig<-Thread -1226200144 mit Arbeit fertig<-Thread -1234592848 mit Arbeit fertig<-Thread -1242985552 mit Arbeit fertig

->Haupt-Thread (ID:-1209412512) fertig ...

Sie können daran erkennen, dass die ersten drei Threads jeweils »abc«, »efg« und »jkl« ausfüh-ren. Alle noch folgenden Threads führen dann »xyz« aus. Zugegeben, das lässt sich elegantermit den Synchronisationsmechanismen der Thread-Bibliothek lösen, aber das Beispieldemonstriert den Sachverhalt der Funktion pthread_equal() recht gut.

10.5.6 pthread_detach – einen Thread unabhängig machen

Das Gegenteil von pthread_join() stellt die Funktion pthread_detach() dar. Mit dieserFunktion legen Sie fest, dass nicht mehr auf die Beendigung des Threads gewartet werden soll.

#include <pthread.h>

int pthread_detach( pthread_t thread );

Page 53: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

362

10

Sie lösen hiermit praktisch den Thread mit der ID thread von der Hauptanwendung los. Siekönnen diesen Vorgang gerne mit den Daemon-Prozessen vergleichen. Dass dieser Threaddann selbstständig ist, ist nichts Magisches, im Grunde »markieren« Sie den Thread damit nur,so dass bei seinem Beenden der Exit-Status und die Thread-ID gleich freigegeben werden.Ohne pthread_detach() würde dies erst der Fall nach einem pthread_join-Aufruf sein.Natürlich bedeutet die Verwendung von pthread_detach(), dass hierbei auch keinpthread_join() mehr auf das Ende des Threads reagiert.

Ein typischer Codeausschnitt, wie Sie einen Thread von den anderen loslösen können, siehtwie folgt aus:

pthread_t a_thread;int ret;.../* Einen neuen Thread erzeugen */ret = pthread_create( &a_thread, NULL,

thread_function, NULL);/* bei Erfolg den Thread abhängen ... */if (ret == 0) {

pthread_detach(a_thread);}

10.6 Die Attribute von Threads und das Scheduling

Wie Sie bereits im Abschnitt zuvor erfahren haben, kann man auch das AttributPTHREAD_CREATE_DETACHED zum Abhängen (detached) von Threads verwenden. Hierzu kön-nen die folgenden Funktionen verwendet werden:

#include <pthread.h>

int pthread_attr_init( pthread_attr_t *attribute );int pthread_attr_getdetachestate( pthread_attr_t *attribute,

int detachstate );int pthread_attr_setdetachestate( pthread_attr_t *attribute,

int detachstate );int pthread_attr_destroy( pthread_attr_t *attribute );

Mit der Funktion pthread_attr_init() müssen Sie zunächst das Attributobjekt attr initiali-sieren. Dabei werden auch gleich die voreingestellten Attribute gesetzt. Um beim Thema»detached« und »joinable« zu bleiben, ist die Voreinstellung hier PTHREAD_CREATE_JOINABLE,hiermit wird also der Thread nicht von den anderen losgelöst und erst freigegeben, wenn ein

Hinweis

Ein Thread, der mit pthread_detach() oder dem Attribut PTHREAD_CREATE_DETACHED von denanderen Threads losgelöst wurde, kann nicht mehr mit pthread_join() abgefangen werden. DerThread läuft praktisch ohne äußere Kontrolle weiter.

Page 54: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die Attribute von Threads und das Scheduling 10.6

363

Thread nach dem Exit-Status diese Threads fragt (mit pthread_join()). Mit der Funktionpthread_attr_getdetachestate() können Sie das »detached«-Attribut erfragen, und mitpthread_attr_setdetachedstate() wird es gesetzt. Neben dem eben erwähntenPTHREAD_CREATE_JOINABLE, was ja auch die Standardeinstellung eines erzeugten Threads ist,können Sie hierbei auch PTHREAD_CREATE_DETACHED verwenden. Das Setzen vonPTHREAD_CREATE_DETACHED entspricht exakt dem Verhalten der Funktion pthread_detach()(siehe Abschnitt 10.5.6) und kann auch stattdessen verwendet werden – da es erheblichkürzer ist. Benötigen Sie das Attributobjekt attr nicht mehr, können Sie es mitpthread_attr_destroy() löschen. Somit machen die Funktionen wohl erst Sinn, wenn Siebereits mit pthread_detach() einen Thread ausgehängt haben und diesen eventuell wiederzurückholen (PTHREAD_CREATE_JOINABLE) müssen.

Bedeutend wichtiger im Zusammenhang mit den Attributen von Threads erscheint hier schondas Setzen der Prozessorzuteilung (Scheduling). Laut POSIX gibt es drei verschiedene solcherProzesszuteilungen (Scheduling Policies):

� SCHED_OTHER – Die normale Priorität wie bei einem gewöhnlichen Prozess. Der Threadwird beendet, entweder wenn seine Zeit um ist und er wartet, bis er wieder am Zuge ist,oder wenn ein anderer Thread oder Prozess gestartet wurde, der mit einer höheren Prio-rität ausgestattet ist.

� Echtzeit (SCHED_FIFO) – Dies sind Echtzeitprozesse. Sie werden in jedem Fall SCHED_OTHER-Prozessen vorgezogen. Auch können sie nicht von normalen Prozessen unterbrochen wer-den. Es gibt drei Möglichkeiten, Echtzeitprozesse zu unterbrechen:

a.) Er wandert in eine Warteschlange und wartet auf ein externes Ereignis.

b.) Er verlässt freiwillig die CPU (z. B. mit sched_yield()).

c.) Er wird von einem anderen Echtzeitprozess mit einer höheren Priorität verdrängt.

� Echtzeit (SCHED_RR) – Dies sind Round-Robin-Echtzeitprozesse. Beim Round-Robin-Verfah-ren hat jeder Prozess die gleiche Zeitspanne zur Verfügung. Ist diese verstrichen, so kommtder nächste Prozess an die Reihe. Unter Linux werden diese Prozesse genauso behandeltwie die Echtzeitprozesse, mit dem Unterschied, dass diese an das Ende der run-queuegesetzt werden, wenn sie den Prozessor verlassen.

Jetzt habe ich hier Echtzeitoperationen ins Spiel geworfen und sollte daher hierzu einen kur-zen Exkurs machen, damit man die Echtzeitstrategie nicht mit »jetzt –gleich sofort« vergleicht.Die Abarbeitung von Daten in der Echtzeit kann einfach nicht sofort ausgeführt werden, son-dern auch hier muss man sich damit begnügen, dass diese innerhalb einer vorgegebenen Zeit-spanne abgearbeitet werden. Allerdings müssen solche Echtzeitoperationen auch unterbrech-bar sein, um auf plötzliche unvorsehbare Ereignisse reagieren zu können. Daher unterscheidetman hier zwischen »weichen« und »harten« Echtzeitanforderungen. Die Anforderungen hän-gen vom Anwendungsfall ab, so kann man bei einem Computerspiel jederzeit »weiche« Echt-zeitanforderungen setzen – was bei Maschinenanforderungen wohl eher katastrophal seinkann. Hier muss innerhalb einer vorgegebenen Zeit reagiert werden. Der Hauptbereich vonEchtzeitanwendungen ist immer noch:

� Multimedia – Audio, Video

� Steuerung, Regelung – Maschinen-, Robotersteuerung

Page 55: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

364

10

Damit eine solche Zuteilungsstrategie auch funktioniert, muss das System diese auchunterstützen. Dies ist gegeben, wenn bei Ihnen die Konstante _POSIX_THREAD_

PRIORITY_SCHEDULING definiert ist. Beachten Sie außerdem, dass die Echtzeit-Zuteilungsstra-tegien SCHED_FIFO und SCHED_RR nur vom Superuser root ausgeführt werden können.

Verändern bzw. erfragen der Zustellungsstrategie können Sie mit den folgenden Funktionen:

int pthread_setschedparam( pthread thread, int policy,const struct sched_param *param);

int pthread_getschedparam( pthread thread, int policy,struct sched_param *param);

Mit diesen Funktionen setzen (set) oder ermitteln (get) Sie die Zustellungsstrategie einesThreads mit der ID thread vom Typ pthread_t. Die Strategie legen Sie mit dem Parameterpolicy fest. Hierbei kommen die bereits beschriebenen Konstanten SCHED_OTHER, SCHED_FIFOund SCHED_RR in Frage. Mit dem letzten Parameter der Struktur sched_param, die sich in derHeaderdatei <bits/sched.h> befindet:

/* Struktur sched_param */struct sched_param {

int sched_priority;};

legen Sie die gewünschte Priorität fest.

Das folgende Beispiel soll Ihnen zeigen, wie einfach es ist, die Zuteilungsstrategie und die Pri-orität zu verändern. Sie finden hierbei zwei Funktionen, eine, womit Sie die Strategie und Pri-orität abfragen können, und eine weitere, womit Sie diese Werte neu setzen können. Aller-dings benötigen Sie für das Setzen Superuser-root-Rechte, was im Beispiel ebenfalls ermitteltwird.

/* thread4.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#define MAX_THREADS 3#define BUF 255

/* Funktion ermittelt die Zuteilungsstrategie ** und Priorität eines Threads */

static void getprio( pthread_t id ) {int policy;struct sched_param param;

printf("\t->Thread %ld: ", id);if((pthread_getschedparam(id, &policy, &param)) == 0 ) {

printf("Zuteilung: ");switch( policy ) {

case SCHED_OTHER : printf("SCHED_OTHER; "); break;case SCHED_FIFO : printf("SCHED_FIFO; "); break;

Page 56: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Die Attribute von Threads und das Scheduling 10.6

365

case SCHED_RR : printf("SCHED_RR; "); break;default : printf("Unbekannt; "); break;

}printf("Priorität: %d\n", param.sched_priority);

}}

/* Funktion zum Setzen der Zuteilungsstrategie ** und Prioriät eines Threads */static void setprio( pthread_t id, int policy, int prio ) {

struct sched_param param;

param.sched_priority=prio;if((pthread_setschedparam( pthread_self(),

policy, &param)) != 0 ) {printf("Konnte Zuteilungsstrategie nicht ändern\n");pthread_exit((void *)pthread_self());

}}

static void thread_prio_demo(void *name) {int policy;struct sched_param param;/*Aktuelle Zuteilungsstrategie und Priorität erfragen */getprio(pthread_self());/* Ändern darf hier nur der root */if( getuid() != 0 ) {

printf("Verändern geht nur mit Superuser-Rechten\n");pthread_exit((void *)pthread_self());

}/* Neue Zuteilungsstrategie und Priorität festsetzen */setprio(pthread_self(), SCHED_RR, 2);/* Nochmals abfragen, ob erfolgreich verändert ... */getprio(pthread_self());/* Thread-Ende */pthread_exit((void *)pthread_self());

}

int main (void) {int i;static int ret[MAX_THREADS];static pthread_t th[MAX_THREADS];

printf("->Haupt-Thread (ID:%ld) gestartet ...\n",pthread_self());

/* Threads erzeugen */for (i = 0; i < MAX_THREADS; i++) {

if (pthread_create ( &th[i],NULL, &thread_prio_demo,NULL) != 0) {

printf ("Konnte keinen Thread erzeugen\n");

Page 57: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

366

10

exit (EXIT_FAILURE);}

}/* Auf die Threads warten */for (i = 0; i < MAX_THREADS; i++)

pthread_join (th[i], &ret[i]);/* Rückgabe der Threads auswerten */for (i = 0; i < MAX_THREADS; i++)

printf("\t<-Thread %ld mit Arbeit fertig\n", ret[i]);printf("->Haupt-Thread (ID:%ld) fertig ...\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread4 thread4.c -lpthread$ ./thread4->Haupt-Thread (ID:-1209412512) gestartet...

->Thread -1209414736: Zuteilung: SCHED_OTHER; Priorität: 0!!! Verändern geht nur mit Superuser-Rechten!!!

->Thread -1217807440: Zuteilung: SCHED_OTHER; Priorität: 0!!! Verändern geht nur mit Superuser-Rechten!!!

->Thread -1226200144: Zuteilung: SCHED_OTHER; Priorität: 0!!! Verändern geht nur mit Superuser-Rechten!!!

<-Thread -1209414736 mit Arbeit fertig<-Thread -1217807440 mit Arbeit fertig<-Thread -1226200144 mit Arbeit fertig

->Haupt-Thread (ID:-1209412512) fertig ...$ suPassword:********# ./thread4->Haupt-Thread (ID:-1209412512) gestartet ...->Thread -1209414736: Zuteilung: SCHED_OTHER; Priorität: 0->Thread -1209414736: Zuteilung: SCHED_RR; Priorität: 2->Thread -1217807440: Zuteilung: SCHED_OTHER; Priorität: 0->Thread -1217807440: Zuteilung: SCHED_RR; Priorität: 2->Thread -1226200144: Zuteilung: SCHED_OTHER; Priorität: 0->Thread -1226200144: Zuteilung: SCHED_RR; Priorität: 2

<-Thread -1209414736 mit Arbeit fertig<-Thread -1217807440 mit Arbeit fertig<-Thread -1226200144 mit Arbeit fertig

->Haupt-Thread (ID:-1209412512) fertig ...

Selbiges (Zuteilungsstrategien und Priorität) können Sie übrigens mit folgenden Funktionenauch über Attributobjekte (pthread_attr_t) setzen bzw. erfragen:

#include <pthread.h>

/* Zuteilungsstrategie verändern bzw. erfragen */int pthread_attr_setschedpolicy( pthread_attr_t *attr,

int policy);

Page 58: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

367

int pthread_attr_getschedpolicy( const pthread_attr_t *attr,int *policy);

/* Priorität verändern bzw. erfragen */int pthread_attr_setschedparam(

pthread_attr_t *attr, const struct sched_param *param );int pthread_attr_getschedparam(

const pthread_attr_t *attr, struct sched_param *param );

Wollen Sie außerdem festlegen bzw. abfragen, wie ein Thread seine Attribute (Zuteilungsstra-tegie und Priorität) vom Erzeuger-Thread übernehmen soll, stehen Ihnen folgende Funktio-nen zur Verfügung:

#include <pthread.h>

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched );

int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched );

Mit den beiden Funktionen phtread_attr_getinheritsched() und phtread_attr_set-inheritsched() können Sie abfragen bzw. festlegen, wie der Thread die Attribute vom»Eltern«-Thread übernimmt. Dabei gibt es zwei Möglichkeiten – PTHREAD_INHERIT_SCHED,was bedeutet, dass der Kind-Thread die Attribute (mitsamt Zuteilungsstrategie und der Priori-tät) des Eltern-Threads übernimmt, und PTHREAD_EXPLICIT_SCHED bedeutet, eben nichts zuübernehmen, sondern das zu verwenden, was in attr als Zuteilungsstrategie und Prioritätfestgelegt ist. Wurden die Attribute des »Eltern«-Threads nicht verändert, so ist der Kind-Thread dennoch (logischerweise) mit denselben Attributen wie der »Eltern«-Thread ausgestat-tet – da Standardattribute.

10.7 Threads synchronisieren

In vielen Fällen, eigentlich bei Threads fast immer, werden ja mehrere parallel laufende Pro-zesse benötigt, die gemeinsame Daten verwenden und/oder austauschen. Einfachstes Beispiel,ein Thread schreibt gerade etwas in eine Datei, während ein anderer Thread daraus etwasliest. Selbes Problem haben Sie auch beim Zugriff auf globale Variablen. Wenn mehrereThreads darauf zugreifen müssen und Sie hierbei keine Vorkehrungen getroffen haben, istnicht vorherzusagen, welcher Thread die Variable gerade bearbeitet. Sind hierbei z. B. mathe-matische Arbeiten auf mehreren Threads aufgeteilt, kann man mit fast 100 %iger Sicherheitsagen, dass das Ergebnis nicht richtig sein wird.

Hierfür sei folgendes einfaches Beispiel gegeben. Zwei Threads greifen auf eine globale Vari-able zu – hier auf einen geöffneten FILE-Zeiger. Ein Thread wird erzeugt, um etwas in dieseDatei zu schreiben, und ein weiterer Thread soll diese wieder auslesen. Ein simples Beispiel,wie es scheint, nur dass es hierbei schon zu Synchronisationsproblemen (Race Conditions)kommt. Aber testen Sie selbst.

Page 59: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

368

10

/* thread5.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>

#define MAX_THREADS 2#define BUF 255#define COUNTER 10000000

/* Globale Variable */static FILE *fz;

static void open_file(const char *file) {fz = fopen( file, "w+" );if( fz == NULL ) {

printf("Konnte Datei %s nicht öffnen\n", file);exit(EXIT_FAILURE);

}}

static void thread_schreiben(void *name) {char string[BUF];

printf("Bitte Eingabe machen: ");fgets(string, BUF, stdin);fputs(string, fz);fflush(fz);/* Thread-Ende */pthread_exit((void *)pthread_self());

}

static void thread_lesen(void *name) {char string[BUF];rewind(fz);fgets(string, BUF, fz);printf("Ausgabe Thread %ld: ", pthread_self());fputs(string, stdout);fflush(stdout);/* Thread-Ende */pthread_exit((void *)pthread_self());

}

int main (void) {static pthread_t th1, th2;static int ret1, ret2;

printf("->Haupt-Thread (ID:%ld) gestartet ...\n",pthread_self());

open_file("testfile");

Page 60: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

369

/* Threads erzeugen */if (pthread_create( &th1, NULL,

&thread_schreiben, NULL)!=0) {fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}/* Threads erzeugen */if (pthread_create(&th2,NULL,&thread_lesen,NULL) != 0) {

fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}

pthread_join(th1, &ret1);pthread_join(th2, &ret2);

printf("<-Thread %ld fertig\n", th1);printf("<-Thread %ld fertig\n", th1);printf("<-Haupt-Thread (ID:%ld) fertig ...\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread5 thread5.c -lpthread$ ./thread5->Haupt-Thread (ID:-1209412512) gestartet...Bitte Eingabe machen: Ausgabe Thread -1217807440: Hallo, das ist ein Test<-Thread -1209414736 fertig<-Thread -1209414736 fertig<-Haupt-Thread (ID:-1209412512) fertig ...$ cat testfileHallo, das ist ein Test

Bei der Eingabe können Sie schon erkennen, dass der Thread »thread_lesen« schon mit seinerAusgabe begonnen hat und sich schon wieder beendet hat, bevor Sie etwas von der Tastatureingeben konnten. Richtig ausgeführt sollte hier folgende Ausgabe bei der Programmausfüh-rung entstehen:

$ ./thread5->Haupt-Thread (ID:-1209412512) gestartet ...Bitte Eingabe machen: Hallo WeltAusgabe Thread -1217807440: Hallo Welt<-Thread -1209414736 fertig<-Thread -1209414736 fertig<-Haupt-Thread (ID:-1209412512) fertig ...

Zugegeben, als echter C-Guru würde Ihnen jetzt hier schon etwas einfallen, z. B. eine »pol-lende« Schleife mit einem sleep() um den Lese-Thread herumzubauen, die immer wiederabfragt, ob fgets() etwas eingelesen hat. Na ja, das wäre wohl nicht im Sinne des Erfinders,und wenn Sie wirklich die Threads für Echtzeitanwendungen verwenden wollen, ist das wohlauch das Ende Ihrer Programmiererkarriere, wenn die Weichenschaltung einer U-Bahn »in

Page 61: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

370

10

einer pollenden Schleife« warten muss, bevor diese gestellt werden kann! Und außerdem gibtes für solche Fälle einige Synchronisationsmöglichkeiten, die Ihnen die Thread-Bibliothekanbietet.

10.7.1 Mutexe

Wenn Sie mehrere Threads starten und diese quasi parallel ablaufen, können Sie nicht erken-nen, wie weit welcher Thread gerade mit der Verarbeitung von Daten ist. Wenn mehrereThreads beispielsweise an ein und derselben Aufgabe abhängig voneinander arbeiten, wirdeine Synchronisation erforderlich. Genauso ist dies erforderlich, wenn Threads globale Vari-ablen oder die Hardware wie z. B. die Tastatur (stdin) verwenden, da sonst ein Thread dieseVariable einfach überschreiben würde, bevor sie noch verwendet wird.

Um Threads zu synchronisieren, haben Sie zwei Möglichkeiten, zum einen mit so genanntenLocks, die Sie in diesem Kapitel mit den Mutexen durchgehen werden, und zum anderen miteinem Monitor. Mit dem Monitor werden so genannte Condition-Variablen verwendet.

Die Funktionsweise von Mutexen ähnelt den Semaphoren bei den Prozessen. Genauer noch:Ein Mutex ist nichts weiter als ein Semaphor, was wiederum nur eine atomare Operation aufeine Variable ist. Trotzdem lassen sich diese aber wesentlich einfacher erstellen. Das Prinzipist simpel. Ein Thread arbeitet mit einer globalen oder statischen Variablen, die für alle ande-ren Threads von einem Mutex blockiert (gesperrt) wird. Benötigt der Thread diese Variablenicht mehr, gibt er diese frei.

Anhand dieser Erklärung dürfte auch klar sein, dass man selbst dafür verantwortlich ist, kei-nen Deadlock zu erzeugen. In folgenden Fällen könnten auch bei Threads Deadlocks auftre-ten:

� Threads können Ressourcen anfordern, obwohl sie bereits Ressourcen besitzen.

� Ein Thread gibt seine Ressource nicht mehr frei.

� Eine Resource ist frei oder im Besitz eines »exklusiven« Threads.

Hinweis

Der Begriff »Mutex« steht für »Mutual Exclusion Device« (= gegenseitiger Ausschluss). Ein Mutex istsomit ohne Besitzer oder gehört genau einem Thread.

Abbildung 10.2 Nur ein Thread kann einen Mutex sperren.

Globale Variable

Mutex

Thread A Thread B

gesperrt blockiert

Zugriff

Page 62: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

371

Im Falle eines Deadlocks kann keiner der beteiligten Threads seine Arbeit mehr fortsetzen,und somit ist meist keine normale Beendigung mehr möglich. Datenverlust kann die Folgesein.

Statische MutexeUm eine Mutex-Variable als statisch zu definieren, müssen Sie diese mit der KonstantePTHREAD_MUTEX_INITIALIZER initialisieren. Folgende Funktionen stehen Ihnen zur Verfü-gung, um Mutexe zu sperren und wieder freizugeben:

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);

Mit pthread_mutex_lock() sperren Sie einen Mutex. Wenn hierbei z. B. ein Thread versucht,mit demselben Mutex ebenfalls eine Sperre einzurichten, so wird dieser so lange blockiert, bisder Mutex von einem anderen Thread wieder mittels pthread_mutex_unlock() freigegebenwird.

Die Funktion pthread_mutex_trylock() ist ähnlich wie pthread_mutex_lock(), nur dassdiese Funktion den aufrufenden Thread nicht blockiert, wenn ein Mutex durch einen anderenThread blockiert wird. pthread_mutex_trylock() kehrt stattdessen mit dem Fehlercode(errno) EBUSY zurück und macht mit der Ausführung des aufrufenden Threads weiter.

Das folgende Beispiel ist dasselbe, wie Sie es schon vom Listing »thread5.c« her kennen, nurdass jetzt das Synchronisationsproblem mithilfe eines Mutex behoben wird. Zuerst wird glo-bal der Mutex mit der Konstante PTHREAD_MUTEX_INITIALIZER statisch initialisiert, undanschließend werden im Beispiel die Sperren dort gesetzt und wieder freigegeben, wo diessinnvoll ist.

/* thread6.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>

#define MAX_THREADS 2#define BUF 255#define COUNTER 10000000

static FILE *fz;

/* Statische Mutex-Variable */pthread_mutex_t fz_mutex=PTHREAD_MUTEX_INITIALIZER;

static void open_file(const char *file) {fz = fopen( file, "w+" );if( fz == NULL ) {

printf("Konnte Datei %s nicht öffnen\n", file);

Page 63: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

372

10

exit(EXIT_FAILURE);}

}

static void thread_schreiben(void *name) {char string[BUF];

printf("Bitte Eingabe machen: ");fgets(string, BUF, stdin);fputs(string, fz);fflush(fz);

/* Mutex wieder freigeben */pthread_mutex_unlock( &fz_mutex );

/* Thread-Ende */pthread_exit((void *)pthread_self());

}

static void thread_lesen(void *name) {char string[BUF];

/* Mutex sperren */pthread_mutex_lock( &fz_mutex );rewind(fz);fgets(string, BUF, fz);printf("Ausgabe Thread %ld: ", pthread_self());fputs(string, stdout);fflush(stdout);

/* Mutex wieder freigeben */pthread_mutex_unlock( &fz_mutex );

/* Thread-Ende */pthread_exit((void *)pthread_self());

}

int main (void) {static pthread_t th1, th2;static int ret1, ret2;

printf("->Haupt-Thread (ID:%ld) gestartet ...\n",pthread_self());

open_file("testfile");

/* Mutex sperren */pthread_mutex_lock( &fz_mutex );

Page 64: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

373

/* Threads erzeugen */if( pthread_create( &th1, NULL, &thread_schreiben,

NULL)!=0) {fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}/* Threads erzeugen */if(pthread_create(&th2,NULL, &thread_lesen, NULL) != 0) {

fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}pthread_join(th1, &ret1);pthread_join(th2, &ret2);

printf("<-Thread %ld fertig\n", th1);printf("<-Thread %ld fertig\n", th1);printf("<-Haupt-Thread (ID:%ld) fertig ...\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread6 thread6.c -lpthread$ ./thread6->Haupt-Thread (ID:-1209412512) gestartet ...Bitte Eingabe machen: Hallo Welt mit MutexeAusgabe Thread -1217807440: Hallo Welt mit Mutexe<-Thread -1209414736 fertig<-Thread -1209414736 fertig<-Haupt-Thread (ID:-1209412512) fertig ...

Natürlich können Sie den Lese-Thread mit pthread_mutex_trylock() als eine nicht blockie-rende Mutex-Anforderung ausführen. Hierzu müssten Sie nur die Funktion »thread_lesen« einwenig umändern. Hier ein solcher möglicher Ansatz:

static void thread_lesen(void *name) {char string[BUF];

/* Versuche Mutex zu sperren */while( (pthread_mutex_trylock( &fz_mutex )) == EBUSY) {

sleep(10);printf("Lese-Thread wartet auf Arbeit ...\n");printf("Bitte Eingabe machen: ");fflush(stdout);

}rewind(fz);fgets(string, BUF, fz);printf("Ausgabe Thread %ld: ", pthread_self());fputs(string, stdout);fflush(stdout);

Page 65: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

374

10

/* Mutex wieder freigeben */pthread_mutex_unlock( &fz_mutex );

/* Thread-Ende */pthread_exit((void *)pthread_self());

}

Hierbei wird versucht, alle zehn Sekunden den Mutex zu sperren. Solange EBUSY zurückgege-ben wird, ist der Mutex noch von einem anderen Thread gesperrt. Während dieser Zeitkönnte der wartende Thread ja andere Arbeiten ausführen (es gibt immer was zu tun). DasProgramm bei der Ausführung mit pthread_mutex_trylock():

$ gcc -o thread7 thread7.c -lpthread$ ./thread7->Haupt-Thread (ID:-1209412512) gestartet ...Bitte Eingabe machen: Lese-Thread wartet auf Arbeit ...Bitte Eingabe machen: Lese-Thread wartet auf Arbeit ...Bitte Eingabe machen: Hallo Mutex, Du bist freiAusgabe Thread -1217807440: Hallo Mutex, Du bist frei<-Thread -1209414736 fertig<-Thread -1209414736 fertig<-Haupt-Thread (ID:-1209412512) fertig ...

Dynamische MutexeWenn Sie Mutexe in einer Struktur verwenden wollen, was durchaus eine gängige Praxis ist,können Sie dynamische Mutexe verwenden. Dies sind dann Mutexe, für die zur Laufzeit mitz. B. malloc() Speicher angefordert wird. Für dynamische Mutexe stehen folgende Funktio-nen zur Verfügung:

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr );

int pthread_mutex_destroy(pthread_mutex_t *mutex);

Mit pthread_mutex_init() initialisieren Sie das Mutex mutex. Mit dem Parameter mutexattrkönnen Sie Attribute für das Mutex verwenden. Wird hierbei NULL angegeben, werden dieStandardattribute verwendet. Auf die Attribute von Mutexen wird in Kürze eingegangen.Freigeben können Sie einen solchen dynamisch angelegten Mutex wieder mitpthread_mutex_destroy(). Hierzu nochmals dasselbe Beispiel wie eben mit »thread6.c«, nurmit dynamisch angelegtem Mutex.

/* thread8.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <pthread.h>#define BUF 255

Page 66: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

375

struct data {FILE *fz;char filename[BUF];pthread_mutex_t mutex;

};

static void thread_schreiben(void *arg) {char string[BUF];struct data *d=(struct data *)arg;

printf("Bitte Eingabe machen: ");fgets(string, BUF, stdin);fputs(string, d->fz);fflush(d->fz);

/* Mutex wieder freigeben */pthread_mutex_unlock( &d->mutex );/* Thread-Ende */pthread_exit((void *)pthread_self());

}

static void thread_lesen(void *arg) {char string[BUF];struct data *d=(struct data *)arg;

/* Mutex sperren */while( (pthread_mutex_trylock( &d->mutex )) == EBUSY) {

sleep(10);printf("Lese-Thread wartet auf Arbeit ...\n");printf("Bitte Eingabe machen: ");fflush(stdout);

}rewind(d->fz);fgets(string, BUF, d->fz);printf("Ausgabe Thread %ld: ", pthread_self());fputs(string, stdout);fflush(stdout);/* Mutex wieder freigeben */pthread_mutex_unlock( &d->mutex );/* Thread-Ende */pthread_exit((void *)pthread_self());

}

int main (void) {static pthread_t th1, th2;static int ret1, ret2;struct data *d;

/* Speicher für die Struktur reservieren */d = malloc(sizeof(struct data));

Page 67: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

376

10

if(d == NULL) {printf("Konnte keinen Speicher reservieren ...!\n");exit(EXIT_FAILURE);

}

printf("->Haupt-Thread (ID:%ld) gestartet ...\n",pthread_self());

strncpy(d->filename, "testfile", BUF);d->fz = fopen( d->filename, "w+" );if( d->fz == NULL ) {

printf("Konnte Datei %s nicht öffnen\n", d->filename);exit(EXIT_FAILURE);

}

/* Mutex initialisieren */pthread_mutex_init( &d->mutex, NULL );/* Mutex sperren */pthread_mutex_lock( &d->mutex );

/* Threads erzeugen */if(pthread_create (&th1,NULL,&thread_schreiben,d) != 0) {

fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}

/* Threads erzeugen */if (pthread_create (&th2,NULL, &thread_lesen, d) != 0) {

fprintf (stderr, "Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}pthread_join(th1, &ret1);pthread_join(th2, &ret2);

/* Dynamisch angelegten Mutex löschen */pthread_mutex_destroy( &d->mutex );

printf("<-Thread %ld fertig\n", th1);printf("<-Thread %ld fertig\n", th1);printf("<-Haupt-Thread (ID:%ld) fertig ...\n",

pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung kann ich mir hier ersparen, da es exakt dem Beispiel»thread6.c« entspricht, nur dass hierbei eben ein dynamischer Mutex statt eines statischenverwendet wurde.

Page 68: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

377

Mutex-AttributeMit den folgenden Funktionen können Sie Mutex-Attribute verändern oder abfragen:

#include <pthread.h>

int pthread_mutexattr_init( pthread_mutexattr_t *attr );int pthread_mutexattr_destroy( pthread_mutexattr_t *attr );int pthread_mutexattr_settype( pthread_mutexattr_t *attr,

int kind );int pthread_mutexattr_gettype(

const pthread_mutexattr_t *attr, int *kind );

Mit dem Mutex-Attribut legen Sie fest, was passiert, wenn ein Thread versuchen sollte, einenMutex nochmals zu sperren, obwohl dieser bereits mit pthread_mutex_lock() gesperrtwurde. Mit der Funktion pthread_mutexattr_init() initialisieren Sie zunächst das Mutex-Attributobjekt attr. Zunächst wird hierbei die Standardeinstellung (PTHREAD_MUTEX_FAST_NP)verwendet. Ändern können Sie dieses Attribut mit pthread_mutexattr_settype(). Damitsetzen Sie die Attribute des Mutex-Attributobjekts auf kind. Folgende Konstanten können Siehierbei für kind verwenden:

� PTHREAD_MUTEX_FAST_NP (Standardeinstellung) – pthread_mutex_lock() blockiert den auf-rufenden Thread für immer. Also ein Deadlock.

� PTHREAD_MUTEX_RECURSIVE_NP – pthread_mutex_lock() blockiert nicht und kehrt soforterfolgreich zurück. Wird ein Thread mit diesem Mutex gesperrt, so wird ein Zähler für jedeSperrung um den Wert 1 erhöht. Damit die Sperrung eines rekursiven Mutex aufgehobenwird, muss dieser ebenso oft freigegeben werden, wie er gesperrt wurde.

� PTHREAD_MUTEX_ERRORCHECK_NP – pthread_mutex_lock() kehrt sofort wieder mit demFehlercode EDEADLK zurück, also ähnlich wie mit pthread_mutex_trylock(), nur dass hiereben EBUSY zurückgegeben wird.

10.7.2 Condition-Variablen (Bedingungsvariablen)

Bedingungsvariablen werden dazu verwendet, auf das Eintreffen einer bestimmten Bedin-gung zu warten bzw. die Erfüllung oder den Eintritt einer Bedingung zu zeigen. Bedingungs-variablen werden außerdem mit den Mutexen verknüpft. Dabei wird beim Warten auf eineBedingung eine Sperre zu einem dazu verknüpften Mutex freigegeben (natürlich musstezuvor eine Sperre auf den Mutex erfolgt sein).

Andersherum sollte vor einem Eintreffen auf einer Bedingung eine Sperre auf den verknüpf-ten Mutex erfolgen, so dass nach dem Warten auf diesen Mutex auch die Sperre auf denMutex wieder vorhanden ist. Erfolgte keine Sperre vor dem Signal, wartet ein Thread wieder,bis eine Sperre auf den Mutex möglich ist.

Hinweis

Da die Variablen hierbei mit dem Suffix _NP (non-portable) verbunden sind, sind diese nicht mit demPOSIX-Standard vereinbar und somit nicht geeignet für portable Programme.

Page 69: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

378

10

Statische BedingungsvariablenFür die Bedingungsvariablen wird der Datentyp pthread_cont_t verwendet. Damit eine sol-che Bedingungsvariable überhaupt als statisch definiert ist, muss diese mit der KonstantePTHREAD_COND_INITIALIZER initialisiert werden. Hier die Funktionen, womit Sie mit Condi-tion-Variablen operieren können:

#include <pthread.h>

int pthread_cond_signal( pthread_cond_t *cond );int pthread_cond_broadcast( pthread_cond_t *cond );int pthread_cond_wait( pthread_cond_t *cond,

pthread_mutex_t *mutex );int pthread_cond_timedwait( pthread_cond_t *cond,

pthread_mutex_t *mutex,const struct timespec *abstime);

Bevor Sie zunächst die Funktion pthread_cond_wait() verwenden, müssen Sie beim aufru-fenden Thread das Mutex mutex sperren. Mit einem anschließenden pthread_cond_wait()wird der Mutex dann freigegeben, und der Thread wird mit der Bedingungsvariablen cond,bis zum Eintreffen einer bestimmten Bedingung, blockiert. Bei einem erfolgreichen Aufrufvon pthread_cond_wait() wird auch für den Mutex automatisch die Sperre wieder eingerich-tet – oder einfach, es herrscht wieder der Zustand wie vor dem pthread_cond_wait-Aufruf.

Threads, die auf die Bedingungsvariable cond warten, können Sie mit phtread_cond_signal() wieder aufwecken und weiter ausführen. Bei mehreren Threads, die auf die Bedin-gungsvariable cond warten, bekommt der Thread mit der höchsten Priorität den Zuschlag.

Wollen Sie hingegen alle Threads aufwecken, die auf die Bedingungsvariable cond warten,können Sie die Funktion pthread_cond_signal() verwenden.

Natürlich gibt es auch noch eine Funktion, womit Sie, im Gegensatz zu phtread_cond_wait(),nur eine gewisse Zeit auf die Bedingungsvariable cond warten, bevor sie zum aufrufendenThread zurückkehrt und wieder automatisch die Sperre von Mutex einrichtet –pthread_cond_timewait(). Als Zeit können Sie hierbei abstime verwenden, womit Sie eineabsolute Zeit in Sekunden und Nanosekunden angeben, die seit dem 1.1.1970 vergangensind.

struct timespec {time_t tv_sec; // Sekundenlong tv_nsec; // Nanosekunden

};

Hierzu ein recht einfaches Beispiel, das rein die Funktionalität von Bedingungsvariablen undvor allem deren Verwendung demonstriert.

/* thread9.c */#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>

Page 70: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

379

#define THREAD_MAX 3

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static void *threads (void *arg) {printf("\t->Thread %ld wartet auf Bedingung\n",

pthread_self());

pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);

printf("\t->Thread %ld hat Bedingung erhalten\n",pthread_self());

printf("\t->Thread %ld: Sende wieder die ""Bedingungsvariable\n", pthread_self());

pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);return NULL;

}

int main (void) {int i;pthread_t th[THREAD_MAX];

printf("->Main-Thread %ld gestartet\n", pthread_self());for(i=0; i<THREAD_MAX; i++)

if (pthread_create (&th[i],NULL, &threads, NULL)!=0) {printf ("Konnte keinen Thread erzeugen\n");exit (EXIT_FAILURE);

}printf("->Main-Thread: habe soeben %d Threads erzeugt\n",

THREAD_MAX);

/* Kurz ruhig legen, damit der Main-Thread als Erstes die* Bedingungsvariable sendet */sleep(1);printf("->Main-Thread: Sende die Bedingungsvariable\n");pthread_cond_signal(&cond);

for(i=0; i<THREAD_MAX; i++)pthread_join (th[i], NULL);

printf("->Main-Thread %ld beendet\n", pthread_self());pthread_exit(NULL);

}

Das Programm bei der Ausführung:

$ gcc -o thread9 thread9.c -lpthread$ ./thread9

Page 71: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

380

10

->Main-Thread -1209416608 gestartet->Main-Thread: habe soeben 3 Threads erzeugt

->Thread -1209418832 wartet auf Bedingung->Thread -1217811536 wartet auf Bedingung->Thread -1226204240 wartet auf Bedingung

->Main-Thread: Sende die Bedingungsvariable->Thread -1209418832 hat Bedingung erhalten->Thread -1209418832: Sende wieder die Bedingungsvariable->Thread -1217811536 hat Bedingung erhalten->Thread -1217811536: Sende wieder die Bedingungsvariable->Thread -1226204240 hat Bedingung erhalten->Thread -1226204240: Sende wieder die Bedingungsvariable

->Main-Thread -1209416608 beendet

Sie sehen hierbei, dass, sobald der Haupt-Thread eine Bedingungsvariable »sendet«, eine Ket-tenreaktion der weiteren Threads entsteht. Hier werden die Threads, entsprechend wie sie inder Queue angelegt wurden, abgearbeitet.

Dazu ein simples Beispiel. In diesem Beispiel wartet der Thread Nummer 2 auf die Condition-Variable von Thread 1. Thread 1 weist einem globalen Zahlenarray werte zehn Werte zu, dieThread 2 anschließend berechnet. Dies ist natürlich auch wieder ein primitives Beispiel undsoll nur die Funktion von Condition-Variablen demonstrieren.

/* thread10.c */#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>

static int werte[10];pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static void thread1 (void *arg) {int ret, i;

printf ("\t->Thread %ld gestartet ...\n",pthread_self ());

sleep (1);ret = pthread_mutex_lock (&mutex);if (ret != 0) {

printf ("Fehler bei lock in Thread:%ld\n",pthread_self());

exit (EXIT_FAILURE);}

/* Kritischer Codeabschnitt */for (i = 0; i < 10; i++)

werte[i] = i;/* Kritischer Codeausschnitt Ende */

Page 72: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

381

printf ("\t->Thread %ld sendet Bedingungsvariable\n",pthread_self());

pthread_cond_signal (&cond);

ret = pthread_mutex_unlock (&mutex);if (ret != 0) {

printf ("Fehler bei unlock in Thread: %ld\n",pthread_self ());

exit (EXIT_FAILURE);}printf ("\t->Thread %ld ist fertig\n",pthread_self());pthread_exit ((void *) 0);

}

static void thread2 (void *arg) {int i;int summe = 0;

printf ("\t->Thread %ld wartet auf Bedingungsvariable\n",pthread_self ());

pthread_cond_wait (&cond, &mutex);printf ("\t->Thread %ld gestartet ...\n",

pthread_self ());for (i = 0; i < 10; i++)

summe += werte[i];printf ("\t->Thread %ld fertig\n",pthread_self());printf ("Summe aller Zahlen beträgt: %d\n", summe);pthread_exit ((void *) 0);

}

int main (void) {pthread_t th[2];

printf("->Main-Thread %ld gestartet\n", pthread_self());

pthread_create (&th[0], NULL, thread1, NULL);pthread_create (&th[1], NULL, thread2, NULL);

pthread_join (th[0], NULL);pthread_join (th[1], NULL);

printf("->Main-Thread %ld beendet\n", pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread10 thread10.c -lpthread$ ./thread10->Main-Thread -1209416608 gestartet

->Thread -1209418832 gestartet ...

Page 73: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

382

10

->Thread -1217811536 wartet auf Bedingungsvariable->Thread -1209418832 sendet Bedingungsvariable->Thread -1209418832 ist fertig->Thread -1217811536 gestartet ...->Thread -1217811536 fertig

Summe aller Zahlen beträgt: 45->Main-Thread -1209416608 beendet

Dynamische BedingungsvariablenNatürlich steht Ihnen hierzu auch die Möglichkeit zur Verfügung, Bedingungsvariablen dyna-misch anzulegen, wie dies häufig mit Datenstrukturen der Fall ist. Hierzu stehen Ihnen die fol-genden Funktionen zur Verfügung:

#include <pthread.h>

int pthread_cond_init( pthread_cond_t *cond,pthread_condattr_t *cond_attr );

int pthread_cond_destroy( pthread_cond_t *cond );

Mit pthread_cond_init() initialisieren Sie die Bedingungsvariable cond mit den über attrfestgelegten Attributen (hierauf wird im nächsten Abschnitt eingegangen). Verwenden Sie fürattr NULL, werden die standardmäßig voreingestellten Bedingungsvariablen verwendet. Frei-geben können Sie die dynamisch angelegte Bedingungsvariable cond wieder mit der Funktionpthread_cond_destroy().

Hierzu dasselbe Beispiel wie schon im Beispiel »thread10.c« zuvor, nur eben als dynamischeVariante.

/* thread11.c */#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>

struct data {int werte[10];pthread_mutex_t mutex;pthread_cond_t cond;

};

static void thread1 (void *arg) {struct data *d=(struct data *)arg;int ret, i;

Hinweis

In diesem und auch in vielen anderen Beispielen wurde das eine oder andere Mal auf eine Fehlerüber-prüfung verzichtet, was man in der Praxis natürlich tunlichst vermeiden sollte. Allerdings würde ein»perfekt« geschriebenes Programm zu viele Buchseiten in Anspruch nehmen.

Page 74: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

383

printf ("\t->Thread %ld gestartet ...\n",pthread_self ());

sleep (1);ret = pthread_mutex_lock (&d->mutex);if (ret != 0) {

printf ("Fehler bei lock in Thread:%ld\n",pthread_self());

exit (EXIT_FAILURE);}

/* Kritischer Codeabschnitt */for (i = 0; i < 10; i++)

d->werte[i] = i;/* Kritischer Codeausschnitt Ende */

printf ("\t->Thread %ld sendet Bedingungsvariable\n",pthread_self());

pthread_cond_signal (&d->cond);

ret = pthread_mutex_unlock (&d->mutex);if (ret != 0) {

printf ("Fehler bei unlock in Thread: %ld\n",pthread_self ());

exit (EXIT_FAILURE);}printf ("\t->Thread %ld ist fertig\n", pthread_self());pthread_exit ((void *) 0);

}

static void thread2 (void *arg) {struct data *d=(struct data *)arg;int i;int summe = 0;

printf ("\t->Thread %ld wartet auf Bedingungsvariable\n",pthread_self ());

pthread_cond_wait (&d->cond, &d->mutex);printf ("\t->Thread %ld gestartet ...\n",

pthread_self ());for (i = 0; i < 10; i++)

summe += d->werte[i];printf ("\t->Thread %ld fertig\n",pthread_self());printf ("Summe aller Zahlen beträgt: %d\n", summe);pthread_exit ((void *) 0);

}

int main (void) {pthread_t th[2];struct data *d;

Page 75: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

384

10

/* Speicher für die Struktur reservieren */d = malloc(sizeof(struct data));if(d == NULL) {

printf("Konnte keinen Speicher reservieren ...!\n");exit(EXIT_FAILURE);

}

/* Bedingungsvariablen initialisieren */pthread_cond_init(&d->cond, NULL);

printf("->Main-Thread %ld gestartet\n", pthread_self());

pthread_create (&th[0], NULL, thread1, d);pthread_create (&th[1], NULL, thread2, d);

pthread_join (th[0], NULL);pthread_join (th[1], NULL);

/* Bedingungsvariable freigeben */pthread_cond_destroy(&d->cond);

printf("->Main-Thread %ld beendet\n", pthread_self());return EXIT_SUCCESS;

}

Hierzu noch ein typisches Anwendungsbeispiel. Wir simulieren ein Programm, das Datenempfängt, und erzeugen dabei zwei Threads. Jeder dieser beiden Threads wird mitpthread_cond_wait() in einen Wartezustand geschickt und wartet auf das Signalpthread_cond_signal() vom Haupt-Thread. Ein einfaches Server-Client-Prinzip also. DerHaupt-Thread simuliert dann, er würde zwei Datenpakete an einen Client-Thread verschicken.Der Client-Thread simuliert anschließend, er würde die Datenpakete bearbeiten. Im Beispielwurden statische Bedingungsvariablen verwendet. Die Ausgabe und der Ablauf des Pro-gramms sollten den Sachverhalt außerdem von selbst erklären:

/* thread12.c */#define _MULTI_THREADED#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#define NUMTHREADS 2

static void checkResults (const char *string, int val) {if (val) {

printf ("Fehler mit %d bei %s", val, string);exit (EXIT_FAILURE);

}}

Page 76: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

385

static pthread_mutex_t dataMutex =PTHREAD_MUTEX_INITIALIZER;

static pthread_cond_t DatenVorhandenCondition =PTHREAD_COND_INITIALIZER;

static int DatenVorhanden = 0;static int geteilteDaten = 0;

static void *theThread (void *parm) {int rc;// Datenpaket in zwei Verarbeitungsschrittenint retries = 2;

printf ("\t->Client %ld: gestartet\n", pthread_self ());rc = pthread_mutex_lock (&dataMutex);checkResults ("pthread_mutex_lock()\n", rc);

while (retries--) {while (!DatenVorhanden) {

printf ("\t->Client %ld: Warte auf Daten ...\n",pthread_self ());

rc = pthread_cond_wait ( &DatenVorhandenCondition,&dataMutex);

if (rc) {printf ("Client %ld: pthread_cond_wait()"

" Fehler rc=%d\n", rc, pthread_self ());pthread_mutex_unlock (&dataMutex);exit (EXIT_FAILURE);

}}printf("\t->Client %ld: Daten wurden gemeldet --->\n"

"\t----> Bearbeite die Daten, solange sie ""geschützt sind (lock)\n", pthread_self ());

if (geteilteDaten == 0) {DatenVorhanden = 0;

}}//Ende while(retries--)

printf ("Client %ld: Alles erledigt\n",pthread_self ());

rc = pthread_mutex_unlock (&dataMutex);checkResults ("pthread_mutex_unlock()\n", rc);return NULL;

}

int main (int argc, char **argv) {pthread_t thread[NUMTHREADS];int rc = 0;// Gesamtanzahl der Datenpaketeint anzahlDaten = 4;int i;

Page 77: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

386

10

printf ("->Main-Thread %ld gestartet ...\n");for (i = 0; i < NUMTHREADS; ++i) {

rc=pthread_create (&thread[i], NULL, theThread, NULL);checkResults ("pthread_create()\n", rc);

}

/* Server-Schleife */while (anzahlDaten--) {

sleep (3); // Eine Bremse zum "Mitverfolgen"printf ("->Server: Daten gefunden\n");

/* Schütze geteilte (shared) Daten und Flags */rc = pthread_mutex_lock (&dataMutex);checkResults ("pthread_mutex_lock()\n", rc);printf ("->Server: Sperre die Daten und gib eine "

"Meldung an Consumer\n");++geteilteDaten; /* Füge "shared" Daten hinzu */DatenVorhanden = 1; /* ein vorhandenes Datenpaket *//* Client wieder aufwecken */rc = pthread_cond_signal (&DatenVorhandenCondition);if (rc) {

pthread_mutex_unlock (&dataMutex);printf ("Server: Fehler beim Aufwecken von "

"Client, rc=%d\n", rc);exit (EXIT_FAILURE);

}printf("->Server: Gibt die gesperrten Daten"

" wieder frei\n");rc = pthread_mutex_unlock (&dataMutex);checkResults ("pthread_mutex_lock()\n", rc);

}//Ende while(anzahlDaten--)

for (i = 0; i < NUMTHREADS; ++i) {rc = pthread_join (thread[i], NULL);checkResults ("pthread_join()\n", rc);

}printf ("->Main-Thread ist fertig\n");return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread12 thread12.c -lpthread$ ./thread12->Main-Thread -1073743916 gestartet...

->Client -1209418832: gestartet->Client -1209418832: Warte auf Daten ...->Client -1217811536: gestartet->Client -1217811536: Warte auf Daten ...

->Server: Daten gefunden

Page 78: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

387

->Server: Sperre die Daten und gib eine Meldung an Consumer->Server: Gibt die gesperrten Daten wieder frei

->Client -1209418832: Daten wurden gemeldet --->----> Bearbeite die Daten, solange sie geschützt sind (lock)->Client -1209418832: Daten wurden gemeldet --->----> Bearbeite die Daten, solange sie geschützt sind (lock)

Client -1209418832: Alles erledigt->Server: Daten gefunden->Server: Sperre die Daten und gib eine Meldung an Consumer->Server: Gibt die gesperrten Daten wieder frei

->Client -1217811536: Daten wurden gemeldet --->----> Bearbeite die Daten, solange sie geschützt sind (lock)->Client -1217811536: Daten wurden gemeldet --->----> Bearbeite die Daten, solange sie geschützt sind (lock)

Client -1217811536: Alles erledigt->Server: Daten gefunden->Server: Sperre die Daten und gib eine Meldung an Consumer->Server: Gibt die gesperrten Daten wieder frei->Server: Daten gefunden->Server: Sperre die Daten und gib eine Meldung an Consumer->Server: Gibt die gesperrten Daten wieder frei->Main-Thread ist fertig

Condition-Variablen-AttributeFür die Attribute von Bedingungsvariablen stehen Ihnen folgende Funktionen zur Verfügung:

#include <pthread.h>

int pthread_condattr_init( pthread_condattr_t *attr );int pthread_condattr_destroy( pthread_condattr_t *attr );

Allerdings machen diese Funktionen noch keinen Sinn, da Linux-Threads noch keine Attri-bute für Bedingungsvariablen anbieten. Diese Funktionen wurden dennoch implementiert,um den POSIX-Standard zu erfüllen.

10.7.3 Semaphore

Threads können auch mit Semaphoren synchronisiert werden. Wie Sie bereits aus dem Kapi-tel zur Interprozesskommunikation erfahren haben, sind Semaphore nichts anderes als nichtnegative Zählvariablen, die man beim Eintritt in einen kritischen Bereich dekrementiert undbeim Verlassen wieder inkrementiert. Hierzu stehen Ihnen folgende Funktionen zur Verfü-gung:

#include <semaphore.h>

int sem_init( sem_t *sem, int pshared, unsigned int value );int sem_wait( sem_t * sem );int sem_trywait( sem_t * sem );int sem_post( sem_t * sem );

Page 79: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

388

10

int sem_getvalue( sem_t * sem, int * sval );int sem_destroy( sem_t * sem );

Alle Funktionen geben bei Erfolg 0 oder bei einem Fehler -1 zurück. Mit der Funktionsem_init() initialisieren Sie das Semaphor sem mit dem Anfangswert value. Geben Sie fürden zweiten Parameter pshared einen Wert ungleich 0 an, kann das Semaphor gemeinsamvon mehreren Prozessen und deren Threads verwendet werden, oder aber, wenn gleich 0 ver-wendet wird, das Semaphor kann nur »lokal« für die Threads des aktuellen Prozesses verwen-det werden.

Die Funktion sem_wait() wird zum Suspendieren eines aufrufenden Threads verwendet.sem_wait() wartet so lange, bis der Zähler sem einen Wert ungleich 0 besitzt. Sobald der Wertvon sem ungleich 0 ist, also z. B. um 1 inkrementiert wurde, kann der suspendierende Threadmit seiner Ausführung fortfahren. Des Weiteren dekrementiert sem_wait, wenn diese Funk-tion »aufgeweckt« wurde, den Zähler des Semaphors wieder um 1. Im Gegensatz zusem_wait() blockiert sem_trywait() nicht, wenn sem gleich 0 ist, und kehrt sofort mit demRückgabewert -1 zurück.

Den Zähler des Semaphors sem können Sie mit der Funktion sem_post() um 1 erhöhen. Wol-len Sie also einen anderen Thread, der mit sem_wait() suspendiert wurde, aufwecken, müs-sen Sie nur sem_post() aus einem anderen Thread aufrufen. sem_post() ist eine nicht blo-ckierende Funktion.

Wollen Sie überprüfen, welchen Wert das Semaphor gerade hat, können Sie die Funktionsem_getvalue() verwenden. Mit der Funktion sem_destroy() löschen Sie das Semaphor semwieder.

Das folgende Beispiel entspricht dem Listing "thread10.c", nur dass hier anstatt Bedingungs-variablen und Mutexen eben ein Semaphor verwendet wird. Mithilfe der Semaphore lässtsich eine Synchronisation (meiner Meinung nach) erheblich einfacher realisieren.

/* thread13.c */#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>#include <semaphore.h>

static int werte[10];sem_t sem;

static void thread1 (void *arg) {int ret, i, val;

printf ("\t->Thread %ld gestartet ...\n",pthread_self ());

/* Kritischer Codeabschnitt */for (i = 0; i < 10; i++)

werte[i] = i;

Page 80: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads synchronisieren 10.7

389

/* Kritischer Codeausschnitt Ende */

/* Semaphor um 1 inkrementieren */sem_post(&sem);/* Aktuellen Wert ermitteln */sem_getvalue(&sem, &val);printf("\t->Semaphor inkrementiert (Wert: %d)\n", val);

printf ("\t->Thread %ld ist fertig\n\n",pthread_self());pthread_exit ((void *) 0);

}

static void thread2 (void *arg) {int i;int summe = 0;

/* Semaphor suspendiert, bis der Wert ungleich 0 ist */sem_wait(&sem);

printf ("\t->Thread %ld gestartet ...\n",pthread_self ());

for (i = 0; i < 10; i++)summe += werte[i];

printf ("\t->Summe aller Zahlen beträgt: %d\n", summe);printf ("\t->Thread %ld fertig\n\n",pthread_self());pthread_exit ((void *) 0);

}

int main (void) {pthread_t th[2];int val;

printf("->Main-Thread %ld gestartet\n", pthread_self());/* Semaphor initialisieren */sem_init(&sem, 0, 0);/* Aktuellen Wert abfragen */sem_getvalue(&sem, &val);printf("->Semaphor initialisiert (Wert: %d)\n\n", val);

/* Mit Absicht anders herum */pthread_create (&th[1], NULL, thread2, NULL);pthread_create (&th[0], NULL, thread1, NULL);

pthread_join (th[0], NULL);pthread_join (th[1], NULL);

/* Aktuellen Wert abfragen */sem_getvalue(&sem, &val);printf("->Semaphor (Wert: %d)\n", val);

Page 81: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

390

10

/* Semphor löschen */sem_destroy(&sem);printf("->Semaphor gelöscht\n");printf("->Main-Thread %ld beendet\n", pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread13 thread13.c -lpthread$ ./thread13->Main-Thread -1209416608 gestartet->Semaphor initialisiert (Wert: 0)

->Thread -1217811536 gestartet ...->Thread -1209418832 gestartet ...->Summe aller Zahlen beträgt: 45->Thread -1209418832 fertig

->Semaphor inkrementiert (Wert: 0)->Thread -1217811536 ist fertig

->Semaphor (Wert: 0)->Semaphor gelöscht->Main-Thread -1209416608 beendet

10.7.4 Weitere Synchronisationstechniken im Überblick

Neben den hier vorgestellten Synchronisationsmechanismen bietet Ihnen die phtread-Biblio-thek noch drei weitere an, worauf hier allerdings nur kurz eingegangen werden soll.

� RW-Locks – Mit RW-Locks (Read-Write-Locks) können Sie es einrichten, dass mehrereThreads aus einem (shared) Datenbereich lesen, aber nur ein Thread zum selben Zeitpunktdarin etwas schreiben darf (one-writer, many-reader). Alle Funktionen dazu beginnen mitdem Präfix pthread_rwlock_.

� Barrier – Als Barrier bezeichnet man einen Punkt, der als (unüberwindbare) Barriere ver-wendet wird, die erst überwunden werden kann, wenn eine bestimmte Anzahl vonThreads an diese Barriere kommt, eben das Prinzip der hohen Mauer bei den Pfadpfindern,die man nur im Team (mit einer gewissen Anzahl von Personen) überwinden kann.Solange eine gewisse Anzahl von Threads nicht vorhanden ist, müssen eben alle Threadsvor der Barriere warten. Soll z. B. ein bestimmter Thread erst ausgeführt werden, wennviele andere Threads parallel mehrere Teilaufgaben erledigt haben, sind Barriers eineprima Synchronisationsmöglichkeit. Alle Funktionen zu den Barriers beginnen mit demPräfix pthread_barrier_.

� Spinlocks – Spinlocks sind nur für Multiprozessorsystemen interessant. Das Prinzip ist das-selbe wie bei den Mutexen, nur dass – anders als bei den Mutexen – ein Thread, der aufeinen Spinlock wartet, nicht die CPU freigibt, sondern eine so genannte »busy Loop«(Schleife) ausführt, bis der Spinlock frei ist. Dadurch bleibt ein Kontexwechsel (Contex

Page 82: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads abbrechen (canceln) 10.8

391

Switch) erspart. Contex Switch: Beim Kontexwechsel wird der Thread blockiert, und alleInformationen, die für das Weiterlaufen benötigt werden, müssen gespeichert werden. Beivielen Kontexwechseln ist dies ein Menge ersparter Zeit, die man mit Spinlocks gewinnenkann. Alle Funktionen zu den Spinlocks beginnen mit dem Präfix pthread_spin_.

10.8 Threads abbrechen (canceln)

Wird ein Thread abgebrochen bzw. beendet, wurde bisher auch der komplette Thread been-det. Doch auch hierbei ist es möglich, auf eine Abbruchaufforderung zu reagieren. Hierzu sinddrei Möglichkeiten vorhanden:

� PTHREAD_CANCEL_DISABLE – Damit legen Sie fest, dass ein Thread nicht abbrechbar ist. Den-noch bleiben Abbruchaufforderungen von anderen Threads nicht unbeachtet. Diese blei-ben bestehen, und es kann ggf. darauf reagiert werden, wenn man den Thread wieder ineinen abbrechbaren Zustand mittels PTHREAD_CANCEL_ENABLE setzt.

� PTHREAD_CANCEL_DEFERRED – Diese Abbruchmöglichkeit ist die Standardeinstellung beiden Threads. Bei einem Abbruch fährt der Thread so lange fort, bis der nächste Abbruch-punkt erreicht wurde. Man spricht von einem »verzögerten« Abbruchpunkt. Einen solchen»Abbruchpunkt« stellten u.a. Funktionen wie pthread_cond_wait(), pthread_cond_timewait(), pthread_join(), pthread_testcancel(), sem_wait(), sigwait(), open(),close(), read(), write() und noch viele weitere mehr da.

� PTHREAD_CANCEL_ASYNCHRONOUS – Hiermit wird der Thread gleich nach dem Eintreffeneiner Abbruchaufforderung beendet. Hierbei handelt es sich um einen asynchronenAbbruch.

Hierzu die Funktionen, womit Sie einem anderen Thread einen Abbruch senden können undwie Sie die Abbruchmöglichkeiten selbst festlegen.

#include <pthread.h>

int pthread_cancel( pthread_t thread );int pthread_setcancelstate( int state, int *oldstate );int pthread_setcanceltype( int type, int *oldtype );void pthread_testcancel( void );

Mit der Funktion pthread_cancel() schicken Sie dem Thread mit der ID thread einenAbbruchaufforderung. Ob der Thread gleich abbricht oder erst beim nächsten Abbruchpunkt,hängt davon ab, ob hier PTHREAD_CANCEL_DEFERRED (Standard) oder PTHREAD_CANCEL_ASYN-CHRONOUS verwendet wird. Bevor sich der Thread beendet, werden noch, falls verwendet, alleExit-Handler-Funktionen ausgeführt.

Mit der Funktion pthread_setcancelstate() legen Sie fest, ob der Thread auf eine Abbruchauf-forderung reagieren soll (PTHREAD_CANCEL_ENABLE = Default) oder nicht (PTHREAD_CANCEL_DISABLE). Im zweiten Parameter oldstate können Sie den zuvor eingestellten Wert für denThread in der übergebenen Adresse sichern – oder, falls nicht benötigt, NULL angeben.

Page 83: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

392

10

Die Funktion pthread_setcanceltype() hingegen legt über den Parameter type fest, ob derThread verzögert (PTHREAD_CANCEL_DEFERRED = Default) oder asynchron (PTHREAD_CANCEL_ASYNCHRONOUS) beendet werden soll. Auch hier können Sie den alten Zustand des Threads inder Adresse oldtype sichern oder NULL verwenden.

Mit der Funktion pthread_testcancel() können Sie überprüfen, ob eine Abbruchauforde-rung anliegt. Lag eine Abbruchbedingung vor, dann wird der Thread tatsächlich auch beendet.Sie können damit praktisch auch einen eigenen Abbruchpunkt festlegen.

Hier zunächst ein einfaches Beispiel zu pthread_cancel().

/* thread14.c */#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <time.h>

pthread_t t1, t2, t3;static int zufallszahl;

static void cancel_test1 (void) {/* Pseudo-Synchronisation, damit nicht ein Thread

beendet wird, der noch gar nicht läuft. */sleep(1);

if (zufallszahl > 25) {pthread_cancel (t3);printf ("(%d) : Thread %ld beendet %ld\n",

zufallszahl, pthread_self(), t3);printf ("%ld zuende\n", pthread_self());pthread_exit ((void *) 0);

}}

static void cancel_test2 (void) {sleep(1); // Pseudo-Synchronisationif (zufallszahl <= 25) {

pthread_cancel (t2);printf ("(%d) : Thread %ld beendet %ld\n",

zufallszahl, pthread_self(), t2);printf ("%ld zuende\n", pthread_self());pthread_exit ((void *) 0);

}}

static void zufall (void) {srand (time (NULL));zufallszahl = rand () % 50;pthread_exit (NULL);

}

Page 84: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads abbrechen (canceln) 10.8

393

int main (void) {if ((pthread_create (&t1, NULL, zufall, NULL)) != 0) {

fprintf (stderr, "Fehler bei ptread_create ...\n");exit (EXIT_FAILURE);

}if((pthread_create(&t2, NULL, cancel_test1, NULL))!=0) {

fprintf (stderr, "Fehler bei ptread_create...\n");exit (EXIT_FAILURE);

}if((pthread_create(&t3, NULL, cancel_test2, NULL))!=0) {

fprintf (stderr, "Fehler bei ptread_create ...\n");exit (EXIT_FAILURE);

}pthread_join (t1, NULL);pthread_join (t2, NULL);pthread_join (t3, NULL);return EXIT_SUCCESS;

}

Hier werden drei Threads erzeugt. Einer der Threads erzeugt eine Zufallszahl, die anderenzwei Threads reagieren entsprechend auf diese Zufallszahl. Je nachdem, ob die Zufallszahlkleiner bzw. größer als 25 ist, beendet der eine Thread den anderen mit pthread_cancel().Wenn Sie das Programm ausführen, wird trotzdem, nach Beendigung einer der beidenThreads mit pthread_cancel(), zweimal ausgegeben:

Thread n beendet

Wie kann das sein, wo Sie doch mindestens einen Thread beendet haben? Das ist die zweiteBedingung zur Beendigung von Threads, nämlich die Reaktion auf die Abbruchanforderun-gen. Die Standardeinstellung lautet hier ja PTHREAD_CANCEL_DEFERRED. Damit läuft der Threadnoch bis zum nächsten Abbruchpunkt, in unserem Fall pthread_exit(). Wenn Sie einenThread sofort abbrechen wollen bzw. müssen, müssen Sie mit pthread_setcanceltype() dieKonstante PTHREAD_CANCEL_ASYNCHRONOUS setzen, z. B. in der main-Funktion mit:

if ((pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS,NULL))!= 0) {

fprintf(stderr, "Fehler bei pthread_setcanceltype\n");exit (EXIT_FAILURE);

}

In der Praxis kann man aber von asynchronen Abbrüchen abraten, da diese an jeder Stelle auf-treten können. Wird z. B. pthread_mutex_lock() aufgerufen und tritt hier der Abbruch ein,nachdem das Mutex gesperrt wurde, hat man schnell einen Deadlock erzeugt. Einen asyn-chronen Abbruch sollte man in der Praxis nur verwenden, wenn die Funktion »asynchronsi-cher« ist, was mit pthread_cancel(), pthread_setcancelstate() und pthread_setcancel-type() nicht allzu viele Funktionen sind. Wenn Sie schon asynchrone Abbrüche verwendenmüssen, dann eben immer wenn ein Thread keine wichtigen Ressourcen beinhaltet (wiereservierter Speicherplatz (Memory Leaks), Sperren etc.).

Ein besonders häufiger Anwendungsfall von PTHREAD_CANCEL_DISABLE sind kritischeCodebereiche, die auf keinen Fall abgebrochen werden dürfen. Zum Beispiel ist dies sinnvoll

Page 85: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

394

10

bei wichtigen Einträgen in Datenbanken, bei komplexen Maschinensteuerungen. Am bestenrealisiert man solche Codebereiche, indem man den kritischen Abschnitt als unabbrechbareinrichtet und gleich danach den alten Zustand wiederherstellt.

int oldstate;

/* Thread als unabbrechbar einrichten */if ((pthread_setcancelstate( PTHREAD_CANCEL_DISABLE,

&oldstate))!= 0) {fprintf(stderr, "Fehler bei pthread_setcancelstate\n");exit (EXIT_FAILURE);

}

/* ----------------------------------------- *//* Hier kommt der kritische Codebereich rein *//* ----------------------------------------- */

/* Alten Zustand des Threads wieder herstellen */if ((pthread_setcancelstate(oldstat, NULL))!= 0) {

fprintf(stderr, "Fehler bei pthread_setcancelstate\n");exit (EXIT_FAILURE);

}

Ein einfaches Beispiel hierzu:

/* thread15.c */#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <time.h>

static void cancel_test (void) {int oldstate;

/* Thread als unabbrechbar einrichten */if ((pthread_setcancelstate( PTHREAD_CANCEL_DISABLE,

&oldstate))!= 0) {printf("Fehler bei pthread_setcancelstate\n");exit (EXIT_FAILURE);

}

printf("Thread %ld im kritischen Codeabschnitt\n",pthread_self());

sleep(5); // 5 Sekunden warten

/* Alten Zustand des Threads wieder herstellen */if ((pthread_setcancelstate(oldstate, NULL))!= 0) {

printf("Fehler bei pthread_setcancelstate\n");exit (EXIT_FAILURE);

}

Page 86: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Erzeugen von Thread-spezifischen Daten (TSD-Data) 10.9

395

printf("Thread %ld nach dem kritischen Codeabschnitt\n",pthread_self());

pthread_exit ((void *) 0);}

int main (void) {pthread_t t1;int *abbruch;

printf("Main-Thread %ld gestartet\n", pthread_self());

if((pthread_create(&t1, NULL, cancel_test, NULL)) != 0) {fprintf (stderr, "Fehler bei pthread_create ...\n");exit (EXIT_FAILURE);

}/* Abbruchaufforderung an den Thread */pthread_cancel(t1);pthread_join (t1, &abbruch);if( abbruch == PTHREAD_CANCELED )

printf("Thread %ld wurde abgebrochen\n", t1);printf("Main-Thread %ld beendet\n", pthread_self());return EXIT_SUCCESS;

}

Das Programm bei der Ausführung:

$ gcc -o thread15 thread15.c -lpthread$ ./thread15Main-Thread -1209416608 gestartetThread -1209418832 im kritischen CodeabschnittThread -1209418832 nach dem kritischen CodeabschnittThread -1209418832 wird abgebrochenMain-Thread -1209416608 beendet

Ohne das Setzen von PTHREAD_CANCEL_DISABLE am Anfang des Threads »cancel_test« würdedas Beispiel keine fünf Sekunden mehr warten und auch nicht mehr ausgeben »Thread –1209418832 nach dem kritischen Codeabschnitt« – am besten testen Sie dies, indem Sie dasVerändern des Cancel-Status auskommentieren oder eben anstatt PTHREAD_CANCEL_DISABLEdie Konstante PTHREAD_CANCEL_ENABLE verwenden.

10.9 Erzeugen von Thread-spezifischen Daten (TSD-Data)

Bei einem Aufruf von Funktionen werden die lokalen Daten auf dem Stack abgelegt und auchwieder abgeholt. Bei den Threads kann man ja solch langlebige Daten entweder mit zusätzli-chen Argumenten an die einzelnen Threads weitergeben oder aber in globalen Variablen spei-chern. Wenn Sie aber z. B. vorhaben, eine Bibliothek für den Multithread-Gebrauch zu schrei-ben, ist dies nicht mehr möglich, da man ja hierbei die Argumentzahl nicht mehr verändernkann, damit auch ältere Programme ohne Threads diese Bibliothek verwenden können und

Page 87: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

396

10

man auch nicht weiß, wie viele Threads die Bibliotheksfunktionen nutzen werden, kann mannun mal keine Aussage darüber machen, wie groß die globalen Daten sein sollen.

Das Ganze vielleicht noch etwas vereinfacht erklärt, es ist einfach nicht möglich, dass globaleund statische Variablen unterschiedliche Werte in den verschiedenen Threads haben können.Aus diesem Grund wurden »Schlüssel« eingeführt – oder auch Thread-spezifische Daten (kurzTSD-Data). Dabei handelt es sich um eine Art Zeiger, der immer auf die Daten verweist, diedem Thread gehören, der eben einen entsprechenden »Schlüssel« benutzt. Beachten Sie aller-dings, dass hierbei immer mehrere Threads den gleichen »Schlüssel« benutzen – nicht jederThread einen extra »Schlüssel«!

Dabei bekommt jeder Thread einen privaten Speicherbereich mit einem eigenen Schlüsselzugeteilt. Dies kann man sich gerne als ein Array von void-Zeigern vorstellen, auf die derThread mit »seinem« Schlüssel zugreifen kann.

Hierzu die Funktionen, womit Sie Thread-spezifische Daten erzeugen bzw. die damit arbeitenkönnen.

#include <pthread.h>

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*) );

int pthread_key_delete( pthread_key_t key );int pthread_setspecific(

pthread_key_t key, const void *pointer );void * pthread_getspecific(pthread_key_t key);

Mit pthread_key_create() erzeugen Sie einen neuen TSD-Schlüssel mit der Speicherstellekey des Schlüssels und (als zweites Argument) entweder NULL oder die Funktion, um den Spei-cher der Daten wieder freizugeben, eine Exit-Handler-Funktion, wenn Sie so wollen.

Mit der Funktion pthread_setspecific() können Sie Daten mit dem TSD-Schlüssel assoziie-ren. Sie legen damit praktisch die TSD-Daten für den TSD-Schlüssel key über den Zeiger poin-ter fest.

Mit der Funktion pthread_getspecific() kann man die Daten aus dem TSD-Schlüssel ausle-sen.

Mit dem folgenden Beispiel werden MAX_THREADS Threads erzeugt, von denen jeder Threadeine Thread-eigene Datei mittels TDS-Daten erzeugt. Im Beispiel wird hierbei nur protokol-liert, dass der Thread gestartet und wieder beendet wurde. Zwischen den beiden Zeilen soll-ten Sie die eigentliche Arbeit des Threads eintragen. Fehler oder sonstige Meldungen dieserArbeit können Sie ebenfalls wieder mit »thread_write« in die für den Thread vorgeseheneDatei schreiben. Dass diese Funktion »nur« mit einem einfachen String aufgerufen werdenkann, ist dem TSD-Schlüssel zu verdanken, der in der Funktion »thread_write« mittelspthread_getspecific() eingelesen wird. Ein simples Grundgerüst eben, womit Sie ohne gro-ßen Aufwand Thread-eigene Logdateien verwenden können.

/* thread17.c */#include <pthread.h>#include <stdio.h>

Page 88: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Erzeugen von Thread-spezifischen Daten (TSD-Data) 10.9

397

#include <stdlib.h>#define MAX_THREADS 3

/* TSD-Datenschlüssel */static pthread_key_t tsd_key;

/* Schreibt einen Text in eine Datei für* jeden aktuellen Thread */void thread_write (const char* text) {/* TSD-Daten lesen */FILE* th_fp = (FILE*) pthread_getspecific (tsd_key);fprintf (th_fp, "%s\n", text);

}

/* Am Ende den Zeiger auf die Datei(en) schließen */void thread_close (void* th_fp) {fclose ((FILE*) th_fp);

}

void* thread_tsd (void* args) {char th_fpname[20];FILE* th_fp;

/* Einen Thread-spezifischen Dateinamen erzeugen */sprintf(th_fpname,"thread%d.thread",(int) pthread_self());/* Die Datei öffnen */th_fp = fopen (th_fpname, "w");if( th_fp == NULL )pthread_exit(NULL);

/* TSD-Daten zu TSD-Schlüssel festlegen */pthread_setspecific (tsd_key, th_fp);

thread_write ("Thread wurde gestartet ...\n");

/* Hier kommt die eigentliche Arbeit des Threads hin */

thread_write("Thread ist fertig ...\n");pthread_exit(NULL);

}

int main (void) {int i;pthread_t threads[MAX_THREADS];

/* Einen neuen TSD-Schlüssel erzeugen - Beim Ende eines* Threads wird die Funktion thread_close ausgeführt */

pthread_key_create (&tsd_key, thread_close);/* Threads erzeugen */for (i = 0; i < MAX_THREADS; ++i)pthread_create (&(threads[i]), NULL, thread_tsd, NULL);

Page 89: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

398

10

/* Auf die Threads warten */for (i = 0; i < MAX_THREADS; ++i)pthread_join (threads[i], NULL);

return EXIT_SUCCESS;}

Das Programm bei der Ausführung:

$ gcc -o thread17 thread17.c -lpthread$ ./thread17$ ls *.threadthread-1209418832.thread thread-1217811536.thread thread-1226204240.thread$ cat thread-1209418832.threadThread wurde gestartet ...

Thread ist fertig ...

10.10 pthread_once – Codeabschnitt einmal ausführen

In den Beispielen bisher haben Sie häufig mehrere Threads gestartet. Manchmal tritt aber eineSituation ein, wo man gewisse Vorbereitungen treffen muss – z. B. eine bestimmte Datei anle-gen, weil mehrere Threads darauf zugreifen müssen oder man eine Bibliotheksroutine entwi-ckelt. Ist es nicht möglich, solche Vorbereitungen beim Start des Haupt-Threads zu treffen,sondern muss man dies in einem der Neben-Threads machen, benötigt man einen Mechanis-mus, wo eine Funktion exakt nur einmal ausgeführt wird, egal wie oft und von welchemThread aus diese aufgerufen wurde. Ein einfaches Beispiel, worauf ich hinauswill:

/* thread18.c */#include <pthread.h>#include <stdio.h>#include <stdlib.h>#define MAX_THREADS 3

void thread_once(void) {printf("Funktion thread_once() aufgerufen\n");

}

void* thread_func (void* args) {printf("Thread %ld wurde gestartet\n", pthread_self());thread_once();printf("Thread %ld ist fertig gestartet\n",

pthread_self());pthread_exit(NULL);

}

int main (void) {int i;pthread_t threads[MAX_THREADS];

Page 90: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

pthread_once – Codeabschnitt einmal ausführen 10.10

399

/* Threads erzeugen */for (i = 0; i < MAX_THREADS; ++i)pthread_create (&(threads[i]), NULL, thread_func, NULL);

/* Auf die Threads warten */for (i = 0; i < MAX_THREADS; ++i)pthread_join (threads[i], NULL);

return EXIT_SUCCESS;}

Das Programm bei der Ausführung:

$ gcc -o thread18 thread18.c -lpthread$ ./thread18Thread -1209418832 wurde gestartetFunktion thread_once() aufgerufenThread -1209418832 ist fertig gestartetThread -1217811536 wurde gestartetFunktion thread_once() aufgerufenThread -1217811536 ist fertig gestartetThread -1226204240 wurde gestartetFunktion thread_once() aufgerufenThread -1226204240 ist fertig gestartet

Beabsichtigt war in diesem Beispiel, dass die Funktion »thread_once« nur einmal aufgerufenwird. Aber wie das für Thread-Programme eben üblich ist, wird die Funktion bei jedemThread aufgerufen. Hier kann man zwar mit den Thread-spezifischen Synchronisationen nach-helfen, aber die Thread-Bibliothek bietet Ihnen hier mit der Funktion pthread_once() eineFunktion an, die einen bestimmten Code nur ein einziges Mal ausführt.

#include <pthread.h>

pthread_once_t once_control = PTHREAD_ONCE_INIT;int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));

Vor der Ausführung von pthread_once() muss man eine statische Variable mit der KonstantePTHREAD_ONCE_INIT initialisieren, bevor man diese an pthread_once() (erster Parameter)übergibt. Als zweites Argument übergeben Sie pthread_once(), die Funktion, die den einmalauszuführenden Code enthält. Wird dieser einmal auszuführende Code ausgeführt, wird diesin der Variablen once_control vermerkt, so dass diese Funktion kein zweites Mal mehr aus-geführt werden kann. Hierzu das Beispiel »thread18.c« nochmals mit phtread_once():

/* thread19.c */#include <pthread.h>#include <stdio.h>#include <stdlib.h>#define MAX_THREADS 3

static pthread_once_t once = PTHREAD_ONCE_INIT;

void thread_once(void) {printf("Funktion thread_once() aufgerufen\n");

Page 91: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

400

10

}

void* thread_func (void* args) {printf("Thread %ld wurde gestartet\n", pthread_self());pthread_once(&once, thread_once);printf("Thread %ld ist fertig gestartet\n",

pthread_self());pthread_exit(NULL);

}

int main (void) {int i;pthread_t threads[MAX_THREADS];/* Threads erzeugen */for (i = 0; i < MAX_THREADS; ++i)pthread_create (&(threads[i]), NULL, thread_func, NULL);

/* Auf die Threads warten */for (i = 0; i < MAX_THREADS; ++i)pthread_join (threads[i], NULL);

return EXIT_SUCCESS;}

Das Programm bei der Ausführung:

$ gcc -o thread19 thread19.c -lpthread$ ./thread19Thread -1209418832 wurde gestartetFunktion thread_once() aufgerufenThread -1209418832 ist fertig gestartetThread -1217811536 wurde gestartetThread -1217811536 ist fertig gestartetThread -1226204240 wurde gestartetThread -1226204240 ist fertig gestartet

Jetzt wird die mit pthread_once() eingerichtete Funktion tatsächlich nur noch einmal ausge-führt.

10.11 Thread-safe (thread-sichere Funktionen)

Die Thread-Programmierung kann nur mit Bibliotheken realisiert werden, die als thread-sicher (thread-safe) gelten. Denn auch die Bibliotheken müssen die parallele Ausführungerlauben, um nicht ins Straucheln zu geraten. Mit der Einführung von Glibc 2.0 wurden dieLinux-Threads in den Bibliotheken implementiert und müssen nicht extra besorgt werden.Somit ist strcmp() – auch wenn schon über 15 Jahre alt – thread-safe.

readdir() hingegen ist z. B. nicht thread-safe. Das Problem mit readdir() ist, wenn mehrereThreads denselben DIR-Zeiger verwenden, dass sie immer den aktuellen Rückgabewert vomzuvor erhaltenen Thread überschreiben. Als Alternative für Funktionen, die nicht als thread-safe gelten (auch wenn es nicht sehr viele sind), wurden thread-sichere Schnittstellen, die in

Page 92: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads und Signale 10.12

401

der Regel mit der Endung _r (reentrante-Funktionen) gekennzeichnet wurden, eingeführt.Die thread-sichere Alternative zu readdir() lautet somit readdir_r().

Die Endung _r zeigt Ihnen außerdem nicht nur, dass die Funktion thread-sicher ist, sondernauch, dass diese Funktion keinen internen statischen Puffer verwendet (der beim Aufruf der-selben Funktion in mehreren Threads jedes Mal überschrieben wird). Hierzu eine kurze Listezu einigen gängigen Reentrante-Funktionen, deren genauere Syntax und Verwendung Siebitte der entsprechenden Man-Page entnehmen.

10.12 Threads und Signale

Signale lassen sich auch mit den Threads realisieren, nur muss man hierbei Folgendes beach-ten:

� Signale, die von der Hardware gesendet werden, bekommt immer der Thread, der dasHardware-Signal gesendet hat.

� Jedem Thread kann eine eigene Signalmaske zugeordnet werden. Allerdings gelten Sig-nale, die mit sigaction() eingerichtet wurden, prozessweit für alle Threads.

Zur Verwendung von Signalen mit den Threads werden folgende Funktionen benötigt:

#include <pthread.h>#include <signal.h>

int pthread_sigmask( int how, const sigset_t *newmask,sigset_t *old_mask );

int pthread_kill( pthread_t thread, int signo );

int sigwait( const sigset_t *set, int *sig );

nicht thread-sicher thread-sicher Bedeutung

getlogin getlogin_r Loginname ermitteln

ttyname ttyname_r Terminalpfadname ermitteln

readdir readdir_r Verzeichniseinträge lesen

strtok strtok_r String anhand Tokens zerlegen

asctime asctime_r Zeitfunktion

ctime ctime_r Zeitfunktion

gmtime gmtime_r Zeitfunktion

localtime localtime_r Zeitfunktion

rand rand_r (Pseudo-)Zufallszahlen generieren

getpwuid getpwuid_r Eintrag in /etc/passwd erfragen (via UID)

getpwnam getpwnam_r Eintrag in /etc/passwd erfragen (via Loginname)

getgrgid getgrgid_r Eintrag in /etc/group erfragen (via GID)

getgrnam getgrnam_r Eintrag in /etc/group erfragen (via Gruppenname)

Tabelle 10.1 Nicht thread-sichere Funktionen und die Alternativen

Page 93: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

402

10

int sigwaitinfo( const sigset_t *set, siginfo_t *info );int sigtimedwait( const sigset_t *set, siginfo_t *info,

const struct timespec timeout );

Mit der Funktion pthread_sigmask() können Sie eine Thread-Signalmaske erfragen oderändern. Im Prinzip entspricht diese Funktion der von sigprocmask(), nur eben auf Threadsund nicht Prozesse bezogen. Abgesehen von den Signalen SIGKILL und SIGSTOP können Sieauch hierzu alle bekannten Signale verwenden. Schlägt die Funktion pthread_sigmask() fehl,wird die Signalmaske des Threads nicht verändert.

Ich empfehle Ihnen, für die Funktion pthread_sigmask() das Kapitel der Signale nochmals(falls nötig) durchzulesen – da das Prinzip ähnlich wie zwischen den Prozessen funktioniert.Als erstes Argument für how wird eine Angabe erwartet, wie Sie die Signale verändern wollen.Mögliche Konstanten hierfür sind SIG_BLOCK, SIG_UNBLOCK und SIG_SETMASK. Als zweitesArgument ist ein Zeiger auf einen Satz von Signalen nötig, der die aktuelle Signalmaskeergänzt, sie entfernt oder die Signalmaske ganz übernimmt. Hierfür kann auch NULL angege-ben werden. Der dritte Parameter ist ein Zeiger auf die aktuelle Signalmaske. Hiermit könnenSie entweder die aktuelle Signalmaske abfragen oder, wenn Sie mit dem zweiten Parametereine neue Signalmaske einrichten, die alte Signalmaske sichern. Aber auch der dritte Parame-ter kann NULL sein. Wenn ein Thread einen weiteren Thread erzeugt, erbt dieser ebenfalls dieSignalmaske. Wollen Sie also, dass alle Threads diese Signalmaske erben, sollten Sie vor derErzeugung der Threads im Haupt-Thread die Signalmaske setzen.

Mit der Funktion pthread_kill() senden Sie dem Thread thread das Signal signo. Hierbeisollte man noch die Besonderheiten mit den Signalen SIGKILL, SIGTERM und SIGSTOP erläu-tern. Diese drei Signale gelten weiterhin prozessweit – senden Sie z. B. mit phtread_kill()das Signal SIGKILL an einen Thread, wird der komplette Prozess beendet, nicht nur derThread. Ebenso sieht dies mit dem Signal SIGSTOP aus – hier wird der ganze Prozess (mit allenlaufenden Threads) angehalten, bis ein anderer Prozess (nicht Thread) SIGCONT an den ange-haltenen Prozess sendet.

Mit sigwait() halten Sie einen Thread so lange an, bis eines der Signale aus der Menge setgesendet wird. Die Signalnummer wird noch in sig geschrieben, bevor der Thread seine Aus-führung fortsetzt. Wurde dem Signal ein Signalhandler zugeteilt, wird nichts in sig geschrie-ben.

Hierzu ein einfaches Beispiel, das Ihnen die Verwendung von Signalen in Verbindung mitThreads demonstriert.

/* thread20 */#include <stdio.h>#include <pthread.h>#include <signal.h>

pthread_t tid2;

void int_handler(int dummy) {printf("SIGINT erhalten von TID(%d)\n", pthread_self());

}

Page 94: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads und Signale 10.12

403

void usr1_handler(int dummy) {printf("SIGUSR1 erhalten von TID(%d)\n", pthread_self());

}

void *thread_1(void *dummy) {int sig, status, *status_ptr = &status;sigset_t sigmask;

/* Kein Signal blockieren - SIG_UNBLOCK */sigfillset(&sigmask);pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);sigwait(&sigmask, &sig);

switch(sig) {case SIGINT: int_handler(sig); break;default : break;

}printf("TID(%d) sende SIGINT an %d\n",

pthread_self(), tid2);/* blockiert von tid2 */pthread_kill(tid2, SIGINT);printf("TID(%d) sende SIGUSR1 an %d\n",

pthread_self(), tid2);/* nicht blockiert von tid2 */pthread_kill(tid2, SIGUSR1);

pthread_join(tid2, (void **)status_ptr);printf("TID(%d) Exit-Status = %d\n", tid2, status);

printf("TID(%d) wird beendet\n", pthread_self());pthread_exit((void *)NULL);

}

void *thread_2(void *dummy) {int sig;sigset_t sigmask;

/* Alle Bits auf null setzen */sigemptyset(&sigmask);/* Signal SIGUSR1 nicht blockieren ... */sigaddset(&sigmask, SIGUSR1);pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);sigwait(&sigmask, &sig);

switch(sig) {case SIGUSR1: usr1_handler(sig); break;default : break;

}printf("TID(%d) wird beendet\n", pthread_self());

Page 95: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

404

10

pthread_exit((void *)99);}

int main(void) {pthread_t tid1;pthread_attr_t attr_obj;void *thread_1(void *), *thread_2(void *);sigset_t sigmask;struct sigaction action;

/* Signalmaske einrichten - alle Signale im ** Haupt-Thread blockieren */

sigfillset(&sigmask); /* Alle Bits ein ...*/pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0);

/* Setup Signal-Handler für SIGINT & SIGUSR1 */action.sa_flags = 0;action.sa_handler = int_handler;sigaction(SIGINT, &action, (struct sigaction *)0);action.sa_handler = usr1_handler;sigaction(SIGUSR1, &action, (struct sigaction *)0);

pthread_attr_init(&attr_obj);pthread_attr_setdetachstate( &attr_obj,

PTHREAD_CREATE_DETACHED );pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL);printf("TID(%d) erzeugt\n", tid1);

- 10 -pthread_attr_setdetachstate( &attr_obj,

PTHREAD_CREATE_JOINABLE);pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL);printf("TID(%d) erzeugt\n", tid2);

sleep(1); // Kurze Pause ...

printf("Haupt-Thread(%d) sendet SIGINT an TID(%d)\n",pthread_self(), tid1);

pthread_kill(tid1, SIGINT);printf("Haupt-Thread(%d) sendet SIGUSR1 an TID(%d)\n",

pthread_self(), tid1);pthread_kill(tid1, SIGUSR1);

printf("Haupt-Thread(%d) wird beendet\n",pthread_self());

// Beendet nicht den Prozess!!!pthread_exit((void *)NULL);

}

Page 96: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Zusammenfassung und Ausblick 10.13

405

Das Programm bei der Ausführung:

$ gcc -o thread20 thread20.c -lpthread$ ./thread20TID(-1209418832) erzeugtTID(-1217815632) erzeugtHaupt-Thread(-1209416608) sendet SIGINT an TID(-1209418832)Haupt-Thread(-1209416608) sendet SIGUSR1 an TID(-1209418832)Haupt-Thread(-1209416608) wird beendetSIGUSR1 erhalten von TID(-1209418832)SIGINT erhalten von TID(-1209418832)TID(-1209418832) sende SIGINT an -1217815632TID(-1209418832) sende SIGUSR1 an -1217815632SIGUSR1 erhalten von TID(-1217815632)TID(-1217815632) wird beendetTID(-1217815632) Exit-Status = 99TID(-1209418832) wird beendet

Dieses Beispiel beinhaltet drei Threads (inklusive dem Haupt-Thread). Im Haupt-Thread wirddie Signalmaske eingerichtet, so dass alle Signale im Haupt-Thread blockiert (SIGBLOCK) wer-den. Als Nächstes werden Signalhandler für SIGINT und SIGUSR1 eingerichtet. »thread_1«wird von den Threads abgehängt erzeugt (detached), und »thread_2« wird nicht von den ande-ren Threads abgehängt. Dann werden im Haupt-Thread die Signale SIGINT und SIGUSR1 anden »thread_1« gesendet, und der Haupt-Thread beendet sich.

»thread_1« (da abgehängt, gerne auch Daemon-Thread) hebt die Blockierung der Signale auf(SIG_UNBLOCK) und wartet auf Signale. Im Beispiel wurde ja bereits zuvor SIGINT und SIGUSR1vom Haupt-Thread gesendet, was die Ausgabe des Signalhandlers auch bestätigt. Sobald also»thread_1« seine Signale bekommen hat, sendet es die Signale SIGINT und SIGUSR1 an»thread_2« und wartet (mittels pthread_join()), bis sich »thread_2« beendet, und gibt denExit-Status von »thread_2« aus, bevor sich »thread_1« ebenfalls beendet.

»thread_2« hingegen hebt nur die Blockierung für SIGUSR1 auf – alle anderen Signale werdenja durch die Weitervererbung des Haupt-Threads weiterhin blockiert. Anschließend wartet»thread_2« auf das Signal. Trifft SIGUSR1 ein, wird der Signalhandler ausgeführt und derThread mit einem Rückgabewert beendet (auf den »thread_1« ja mit pthread_join() wartet).

10.13 Zusammenfassung und Ausblick

Thread ist sicherlich ein ziemliches Schlagwort in den letzten Jahren geworden, und viele Pro-grammierer sind in zwei Lager gespalten – in die Befürworter und die Gegner von Threads.Zugegeben, Threads haben je nach Anwendungsfall auch ihre Macken. Gerade in der Netz-werkprogrammierung sorgen Threads bezüglich der Skalierbarkeit immer wieder für Diskus-sionsstoff. Das Problem besteht darin, dass es bei Threads häufig ein hartes Limit der gleich-zeitigen Threads gibt.

Page 97: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Threads

406

10

Wie dem auch sei, trotzdem lassen sich die Hersteller von namhafter Software wie den Server-anwendungen BIND, Apache etc. nicht aufhalten, Thread-Unterstützung in ihre Software ein-zubauen.

Ob Sie nun Threads in Ihre Software einbauen wollen oder nicht, müssen Sie letztendlichselbst entscheiden und hängt größtenteils auch von der Art der Software ab. Am besten wärees sicherlich, wenn Sie Ihre Software mit Thread-Unterstützung anbieten – sprich, der Anwen-der kann diese bei Bedarf aktivieren bzw. testen.

Mit diesem Kapitel haben Sie auf jeden Fall ein fundiertes Polster an Wissen, so dass Sie Soft-ware mit Thread-Unterstützung schreiben können. Aber wie auch bei fast jedem Thema einesBuches gibt es immer noch einiges mehr, das man zu den Threads noch hätte schreiben kön-nen. Aber immerhin, im Gegensatz zur ersten Auflage des Buches wurde der Umfang desKapitels hier verdoppelt.

Page 98: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

1225

Index

$! 996$# 996, 1001$$ 996$* 996$? 996$@ 996$0 996$1 996$1, $2, ... $9 1000& (Hintergrundprozess) 956* (Shell) 972/dev-Verzeichnis 149/etc/group 179

Struktur 180/etc/gshadow 179/etc/hosts 439/etc/inittab 243/etc/ld.so.conf 884/etc/passwd 169/etc/resolv.conf 439/etc/services 443/etc/shadow 169, 174

Struktur 175/etc/shells 170/etc/skel 184/etc/syslog.conf 236/proc

/proc/$pid/cmdline 136/proc/$pid/cwd 139/proc/$pid/environ 137/proc/$pid/exe 139/proc/$pid/fd/ 138/proc/$pid/maps 139/proc/$pid/root 139/proc/$pid/stat 139/proc/$pid/statm 139/proc/$pid/status 139/proc/apm 133/proc/cpuinfo 131/proc/devices 132/proc/dma 132/proc/filesystems 146/proc/ide/ 133/proc/interrupts 132/proc/ioports 133/proc/loadavg 133/proc/locks 145/proc/meminfo 129, 132

/proc (Forts.)/proc/modules 145/proc/mounts 133, 146/proc/mtab 146/proc/net/ 133/proc/scsi 133/proc/scsi/scsi 133/proc/self 137/proc/stat 133/proc/sys/dev/cdrom/autoeject

140/proc/sys/kernel/ctrl-alt-del 140/proc/sys/kernel/osrelease 140/proc/sys/kernel/ostype 140/proc/sys/kernel/version 140/proc/uptime 133/proc/version 129Filesystem 146Hardware-/Systeminformatio-

nen 131Informationen abfragen 129Kernelinformationen 139Prozessinformationen 135

/proc-Verzeichnis 129/usr/bin 859/usr/local/bin 859<< (Shell) 1033<arpa/inet.h> 1139<assert.h> 1088<complex.h> 1107<conio.h> 680<ctype.h> 1088<curses.h> 673, 679<dirent.h> 99, 1121<dlfcn.h> 886<errno.h> 47, 112, 1089<fenv.h> 1107<float.h> 1090<glib.h> 720<inttypes.h> 1109<iso646.h> 1105<libpq-fe.h> 1146<limits.h> 47, 1091<limits.h> (POSIX) 1112<locale.h> 1091<math.h> 1094<math.h> C99 1110<netdb.h> 1140

<netinet/in.h> 433, 1138<pthread.h> 1132<regex.h> 106<setjmp.h> 1095<signal.h> 1096<stdarg.h> 87, 1096<stdbool.h> 1109<stddef.h> 1097<stdint.h> 1109<stdio.h> 84, 1098<stdlib.h> 1100<string.h> 1102<sys/mman.h> 1116<sys/socket.h> 1136<sys/stat.h> 115, 1122<term.h> 673<termios.h> 654<tgmath.h> 1112<time.h> 126, 923, 1104<unistd.h> 1113<wchar.h> 1106<wctype.h> 1106? (Shell) 973[ (Kommando) 1012_Exit 1102_Exit() 1102_IOFBF 91_IOLBF 91_IONBF 91_POSIX_CHOWN_RESTRICTED

1113_POSIX_JOB_CONTROL 1113_POSIX_NO_TRUNC 1113_POSIX_PRIORITY_SCHEDULING

194_POSIX_SAVED_IDS 1113_POSIX_SOURCE 1113_POSIX_THREAD_PRIORITY_

SCHEDULING 364_POSIX_VERSION 1113_XOPEN_VERSION 1113~ (Shell) 9750_EXCL 93

A

Abdeckungsanalyse 927abort() 1101

Page 99: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1226

abs() 1101accept() 421, 1136access() 1124acos() 1094ACS_-Sonderzeichen 686addch() 687addnstr() 689addstr() 689Advisory Locking 68AF_APPLETALK 417AF_ATMPCV 417AF_AX25 417AF_INET 416AF_INET6 416AF_INIX 416AF_IPX 416AF_LOCAL 416AF_NETLINK 416AF_PACKET 417AF_UNIX 416AF_X25 417afio 1190AIX 30–31alarm() 268, 1129alias 1221Allegro 853alphasort() 104ANSI C 37, 1087ANSI C99 1105ANSI-Steuersequenzen 672apropos 1219ar 881ARG_MAX 1113arp 1206arpa 1139Array

Shell 989AS 860asctime() 1104ash 954A-Shell 954asin() 1094asnprintf() 87asprintf() 87Assembler 860assert 1088at 1173atan() 1094atan2() 1094atexit() 742, 1101atof() 1100atoi() 1100

atol() 1100atoll() 1102Atomare Operation 265Atomare Variable 265attroff() 696attron() 696attrset() 696Ausführrechte 1071Ausgaben verknüpfen

Shell 967AUTOCONF 949AUTOMAKE 949awk 988

B

Back Quotes 998badblocks 1180basename 1168Bash 954batch 1173bc 1221

wissenschaftliches Rechnen 982Benutzerdatenbank 169bg 250, 1174

Shell 1060Bibliotheken 880

Dynamisch nachladen 886Dynamische 883Erstellen 880Shared Libraries 883Statische 880

Big-Endian 425Bildschirm ab Cursor löschen 690Bildschirm löschen 677, 690Binäres Lesen und Schreiben 88bind() 420, 1136

Verwenden oder weglassen 496Blockgröße 55, 124Bourne-Shell 953box() 701Brace Extension

Shell 974BSD 30–31

FreeBSD 30–31NetBSD 31OpenBSD 31

bsearch() 1101btowc() 1089Buffer Overflow 89, 942, 1071bunzip2 1190

bzcat 1151bzip2 1190

C

C99 1105cal 1202calloc() 1101can_change_colors() 697case

Shell 1020cat 1151cbreak() 681cd 1168ceil() 1094cfdisk 1181cfgetispeed() 667cfgetospeed() 667cfmakeraw() 665cfsetispeed() 669cfsetospeed() 669CHAR_BIT 1091CHAR_MAX 1091CHAR_MIN 1091chdir() 95, 1121chgrp 1152CHILD_MAX 1113chmod 1153chmod() 82, 117, 1124chown 1154chown() 1124chroot() 1075chtype 687cksum 1152clear 1217clear() 690clearenv() 206, 1125clearerr() 90, 1100clearok() 691clock() 1104close() 52, 423, 1114closedir() 100, 103, 1121closelog() 236Close-on-exec Flag 62close-on-exec-Flag 59, 291clrtobot() 690clrtoeol() 690cmp 1154COLOR_PAIR() 698comm 1154Compiler

GCC 33, 859

Page 100: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1227

complex 1107compress 1190Condition-Variablen 377conio 680connect() 418, 1136Copy on write-Verfahren 212copysign() 1110Core Dump 1082cos() 1094cosh() 1094cp 1155cpio 1190creat() 51cron 1174cron-Job 252crypt 1193csh 953C-Shell 953

Erweiterung 955csplit 1156ctermid() 665ctime() 1104ctype 1088curses 673, 679curses-Bibliothek 679Cursor positionieren 677, 686Cursortasten 684cut 1156

Shell 984CVS 898, 908

Arbeitskopie auschecken 911Archiv einrichten 909Datei entfernen 921Datei hinzufügen 920Datei umbennenen 921Grafische Frontends 922Konflikte 915Neues Projekt einrichten 910Remote-Zugriff 922Repository 909Veränderungen einbringen 913Veränderungen rückgänig

machen 919Veränderungen untersuchen 913Veränderungen weitergeben 914Verzeichnis entfernen 922Verzeichnis hinzufügen 920

D

Dämoncron 232

Dämon (Forts.)div. Netzwerkdämons 233Drucker (lpd, cupsd) 232Erzeugen 238klogd 233syslogd 233xinetd 232

Dämonprozess 232dash 954date 1202Datei

Beschneiden 81Binäres Lesen 88Binäres Schreiben 88Dateiart ermitteln 116Eigentümer 119Größe ermitteln 124Gruppeneigentümer 119Lesen 55Lesen mehrerer Puffer 79Link 120Löschen 92Neu anlegen 48, 51Öffnen 46, 85Positionieren 57, 90Schließen 52, 85Schreiben 52Schreiben mehrerer Puffer 79Sperren 66Status ermitteln (Shell) 1015Temporäre- 1074Temporäre Dateien erstellen 93Umbenennen 92Zeitstempel (Inode-Änderung)

125Zeitstempel (Lesezugriff) 125Zeitstempel (Schreibzugriff) 125Zugriffsrechte 48, 1069Zugriffsrechte erfragen 116Zugriffsrechte verändern 82

Dateisperren 281Dateitabelleneintrag 46Datenbankprogrammierung 519Datenbankserver 521Datenbanksystem

ADABAS-D 522Attribut und Attributname 520Beziehungstypen 520Domäne 520Entität 520Grad der Relation 520Informix 522

Datenbanksystem (Forts.)Kardinalität 520Msql 522Normalisierungstheorie 521Oracle 522Relation 520Relationales 519SQL 521SQL-Server 522Sybase 522Transaktionen 522Tupel 520

DBL_DIG 1090DBL_EPSILON 1091DBL_MANT_DIG 1090DBL_MAX 1091DBL_MAX_10_EXP 1090DBL_MAX_EXP 1090DBL_MIN 1091DBL_MIN_10_EXP 1090DBL_MIN_EXP 1090dd 1181dd_rescue 1183DDD 930Deadlocks 282Debuggen 865, 929

DDD 930GDB 930

delch() 690delwin() 701dev 149Devices 149Dezimalzahl

Shell 979Dezimalzahlen vergleichen

Shell 1012df 1179DIFF 949diff 1156diff3 1157difftime() 1104dig 1210DIR 100dircmp 1168dirent 99, 1121dirent-Struktur 1121dirfd() 100dirname 1168div() 1101dlclose() 886dlerror() 886dlopen() 886

Page 101: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1228

dlsym() 886dmesg 1203dos2unix 1157DoS-Attacken 209Double Quotings 997DOXYGEN 949Druckerbefehle 1205DT_BLK 98DT_CHR 98DT_DIR 98DT_FIFO 98DT_REG 98DT_SOCK 98DT_UNKNOWN 98DTTOIF() 99du 1179dump 1193dumpe2fs 1183dup() 59, 291, 1114dup2() 59, 291, 1114dupwin() 701

E

E2BIG 1090e2fsck 1184EACCES 1090EBADF 1090echo

Shell 1028echo() 682ECONTR 1089ECURDIR 1089EDOM 1089EEXIST 1090EFAULT 1090efence 942EGID 189Eingabe

Shell 1031Einschränkungsmaske 50

Setzen und Abfragen 50EINVACC 1089EINVAL 1090EINVDAT 1089EINVDRV 1089EINVENV 1089EINVFMT 1089EINVFNC 1089EINVMEM 1089Elementare E/A-Funktionen 43

elifShell 1010

elseShell 1010

EMFILE 1090endgrent() 182endpwent() 173endspent() 176endwin() 680ENMFILE 1090ENODEV 1090ENOENT 112, 1090ENOEXEC 1090ENOFILE 1089ENOMEM 1090ENOPATH 1089ENOTSAM 1089env 1221ERANGE 1089erase() 690errno 47, 112, 1089Ersatzmuster

Shell 972Escape-Sequenzen 676ESUCCESS 112etc 169–170, 174–175, 179–180,

184EUID 189EWOULDBLOCK 510EXDEV 1090exec

Shell 1043execl() 226, 1126execle() 226, 1126execlp() 226, 1126execv() 226, 1126execve() 226execvp() 226, 1126exit 1169

Shellkommando 963exit() 1101exp() 1094expand 1158export 991EZERO 1089

F

F_DUPFD 62F_GETFD 62F_GETFL 63F_GETLK 70

F_GETOWN 64F_RDLCK 70F_SETFD 63F_SETFL 64F_SETLK 70F_SETLKW 71F_SETOWN 64F_UNLCK 70F_WRLCK 70fabs() 1094Farbe 696fchdir() 95, 1121fchmod() 82, 1124fchown() 1124fclose() 85, 1098fcntl() 61, 67, 69, 287, 1114FD_CLR() 75, 464, 1115

Sicherheit 1085FD_ISSET() 75, 464, 1115FD_SET() 75, 464, 1115

Sicherheit 1085FD_ZERO() 75, 464, 1115fdformat 1184fdisk 1185fdopen() 83, 85, 1114feclearexcept() 1107fegetenv() 1108fegetexceptflag() 1107fegetround() 1108Fehlerbehandlung 112feholdexcept() 1108fenv 1107feof() 88–89, 1100feraiseexcept() 1107ferror() 88–89, 1100fesetenv() 1108fesetexceptflag() 1107fesetround() 1108fetestexcept() 1107feupdateenv() 1108fflush() 91, 214, 1098fg 250, 1174

Shell 1058fgetc() 88, 1099fgetpos() 90, 1100fgets() 88, 1100FIFO-Pipes 277, 303

Kommunikation nichtverw. Prozesse 311

file 1158File-Deskriptor

Shell 1043

Page 102: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1229

Filedeskriptor 44/proc/$pid/fd/ 138Duplizieren 59, 62Eigenschaften abfragen 61Eigenschaften ändern 61

fileno() 83, 1114Filesystem 146FILE-Zeiger 84find 1159finger 1169float 1090floor() 1094FLT_DIG 1090FLT_EPSILON 1091FLT_MANT_DIG 1090FLT_MAX 1090FLT_MAX_10_EXP 1090FLT_MAX_EXP 1090FLT_MIN 1091FLT_MIN_10_EXP 1090FLT_MIN_EXP 1090FLT_RADIX 1090FLTK 848FLUID 849Flushing, fflush() 92Flusskontrolle 282fma() 1111fmax() 1110fmin() 1110fmod() 1095fold 1159fopen() 85, 1098fork() 211, 449, 1126Formatierte Ausgabe 86Formatierte Eingabe 87for-Schleife

Shell 1022fprintf() 86, 1099fputc() 88, 1099fputs() 88, 1100fread() 88, 1100free 1180free() 1101freopen() 85, 1098frexp() 1094fscanf() 87, 1099fsck 1186fseek() 57, 90, 1100fsetpos() 90, 1100fstat() 82, 115, 1123fsync() 81ftell() 90, 1100

ftok() 319FTP 414ftruncate() 81fts() 109ftw() 108, 1122FTW_D 109FTW_DNR 109FTW_F 109FTW_NS 109FTW_SL 109Funktion

Shell 1050Funktionsreferenz 1087

ANSI C 1087C99 1105Elementare E/A-Funktionen

1112Verzeichnis-Funktionen 1120

Funktionstasten 684fwrite() 88, 1100

G

g_array_append_vals() 736g_array_free() 736g_array_index() 736g_array_insert_vals() 736g_array_new() 736g_array_prepend_vals() 736g_array_remove_index() 736g_assert() 723g_error() 722g_filename_from_utf8() 832g_free() 725g_list_append() 809g_malloc() 725g_malloc0() 725g_memdup() 726g_message() 722g_new() 727g_new0() 727g_object_get() 784, 809g_object_new() 742, 752g_object_set() 784, 809g_print() 722g_printerr() 722g_realloc() 725g_renew() 727g_return_if_fail() 724g_return_val_if_fail() 724g_set_print_handler() 722g_set_printerr_handler() 722

g_signal_connect() 744–745g_signal_connect_swapped() 804g_snprintf() 729G_STR_DELIMITERS 730g_strcasecmp() 728g_strchomp() 730g_strchug() 730g_strconcat() 729g_strdelimit() 730g_strdown() 728g_strdup() 729g_strdup_printf() 729g_strdup_vprintf() 729g_strerror() 722g_string_append() 732g_string_append_c() 732g_string_assign() 732g_string_erase() 732g_string_free() 732g_string_insert() 732g_string_insert_c() 732g_string_new() 732g_string_prepend() 732g_string_prepend_c() 732g_string_sized_new() 732g_strjoin() 729g_strncasecmp() 728g_strndup() 729g_strreverse() 728g_strup() 728g_timer_destroy() 735g_timer_elapsed() 735g_timer_new() 734g_timer_reset() 735g_timer_start() 734g_timer_stop() 735g_try_malloc() 725g_try_realloc() 725g_warning() 722GCC 33, 859

Assembler 860Dateiendungen 862Debuggen 865Linken von Bibliotheken 861Linker 860Optimierungs-Optionen 865Präprozessor 859Präprozessor-Optionen 865Profiling 865Übersetztung in Einzelschritten

863Warnmeldungs-Optionen 864

Page 103: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1230

GCOV 927GDB 865, 930

Ausführen 931Ausführung fortsetzen 934Datenausgabe 937Einzelschritte 935Haltepunkte setzen 933Haltepunkte verwalten 935Inhalt einer Datei anzeigen 932Programm übersetzten 930Variablen prüfen 938Variablen verändern 938

GDK 716Eventmaske 835Events 833Xlib 716

GdkPixbuf 764Gerätedatei 149

/dev-Verzeichnis 149block device 149character device 149major Nummer 150minor Nummer 150Namen 152Spezielle 153

GETALL 326getbegyx() 702getc() 88, 1099getch() 682getchar() 88, 1099getcwd() 97, 1121getdtablesize() 1080getegid() 209, 1125getenv() 201, 1101, 1125geteuid() 209, 1125getgid() 209, 1125getgrent() 182gethostbyaddr() 439, 1140gethostbyname() 439, 1140gethostbyname2() 1140getmaxyx() 702getmouse() 707GETNCNT 326getnstr() 684getopts

Shell 1004getpeername() 1138GETPID 326getpid() 209, 1125getppid() 209, 1125getpriority() 192getpwent() 173

getpwnam() 171getpwuid() 171getrlimit() 207, 1125getrusage() 209, 1125gets() 88, 1099getservbyname() 428, 443, 1141getservbyport() 443, 1141getsockname() 1138getsockopt() 486, 1137getspent() 176getspnam() 178getstr() 684getuid() 209, 1125GETVAL 326getyx() 693GETZCNT 326GID 189GIMP 715GLADE 844Gleitpunktzahlen

Kategorie (C99) 1111Makros (C99) 1111Vergleichen 1111

Gleitpunktzahlen-Umgebung 1107

Glib 716UTF-8 831

Glib Bibliothek 720Array (dynamisch) 736Assertions-Funktionen 723Ausgabe 722Binäre Bäume 740Datentypen 720Hashtabellen 740Listen 740Makros zur Speicherverwaltung

726Quarks 727Speicherblöcke kopieren 726Speicherklumpen 727Speicherverwaltung 725Stringbearbeitung 727Stringpuffer (dynamisch) 731Strings kopieren 729Timer 734

gmtime() 1104GNOME-Desktop 717GNU-Assembler 860GNU-Projekt 32GPROF 865, 924

Flaches Profil 925Profil anlegen 924

GPROF (Forts.)Strukturiertes Profil 926

groupadd 1170groupdel 1170Group-ID-Bit 119groupmod 1170groups 1170grp.h 180Gruppendatenbank 179GTK 715

GNOME 717gtk-config 719pkg-config 719Schnittstellen 717Übersetzten 719

GTK-- (gtkmm) 841GTK+ Bibliothek

Anwendung beenden 745Anzeige-Elemente 758Callbackfunktion 743Container 747Eigenschaften von Widgets 743Events 743, 748, 833Grafiken 764Grundlagen 741Initialisieren 741Klassen-Baum 744Pango 761Repertoire 783Ressource-Files 839Signal für Buttons 784Signale 743, 748, 839Stock Items 839Stock-Element 806Umlaute 749UTF-8 749Verarbeitungsschleife 748Verarbeitungsschleife beenden

749Widget erzeugen 742Widgets packen 747

GTK+ WidgetAbkürzungsbuchstabe 805Accelerator 801, 804–805Anzeigen 748Auswählen 824Bäume und Listen 838Behälter 747, 765, 767, 773Box 765Button 777Button-Box 772Checkbutton 777

Page 104: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1231

GTK+ Widget (Forts.)Combobox 808Container 747Dateiauswahl 824, 831Dateneingabe 785Dialogbox 753Drag and Drop 839Eigenschaften 743Eigenschaften abfragen 784Eigenschaften verändern 784Erzeugen 742Farbauswahl 824Fenster 750Fenster-Eigenschaften 752Fortschrittbalken 765Grafiken anzeigen 764Hierarchische Anordnung 747Lineal 839Löschen 748Menü 795, 800Notizbuch 771Optionsmenü 808Packen 747Radio-Buttons 777, 783Schiebeleiste 770Schieberegler 785, 792Schriftauswahl 824Scrollendes Fenster 823Signale für Buttons 784Statusleiste 764Stellgröße 794Tabelle 773Tastatur-Shortcuts 804Text (mehrzeilig) 812Text(editor) 820Textdarstellung (Eigenschaften)

822Textfelder 785, 791Textlabel 760Textlabel-Eigenschaften 760Text-Tags (Eigenschaften) 820Textwidget-System 812Toolbar 795, 805Tooltipp 806Trennlinie 763Umschaltbutton 777Unterstriche 805Verstecken 748Zahlenfelder 785, 793Zwischenablage 839

gtk_adjustment_clamp_page() 794

gtk_adjustment_get_value() 794gtk_adjustment_new() 794gtk_adjustment_set_value() 794gtk_box_pack_defaults() 748gtk_box_pack_start_defaults()

766gtk_combo_set_popdown_

strings() 809gtk_container_add() 747gtk_dialog_new_with_buttons()

755gtk_dialog_run() 757gtk_exit() 749gtk_file_selection_get_selections()

832GTK_HSCALE 785gtk_init() 741gtk_item_factory_create_items()

800, 803gtk_item_factory_create_new()

800gtk_item_factory_get_widget()

803gtk_item_factory_new() 803gtk_item_factory_path_from_

widget() 803gtk_main() 748gtk_main_quit() 749gtk_menu_append() 808gtk_menu_item_new_with_

label () 808gtk_menu_shell_append() 808gtk_message_dialog_new() 807gtk_notebook_append_page_

menu() 771gtk_notebook_insert_page_

menu() 771gtk_notebook_prepend_page_

menu() 771gtk_notebook_remove_page()

771gtk_option_menu_get_history()

808gtk_option_menu_set_history()

808gtk_pack_box_end() 766gtk_pack_box_start() 766gtk_paned_add1() 770gtk_paned_add2() 770gtk_paned_pack1() 770gtk_paned_pack2() 770gtk_signal_connect() 744

gtk_statusbar_get_contex() 764gtk_statusbar_pop() 764gtk_statusbar_push() 764gtk_statusbar_remove() 764gtk_statusbar_set_has_resize_

grip() 764gtk_table_attach() 775gtk_table_attach_defaults() 775gtk_text_buffer_apply_tag_by_

name() 821gtk_text_buffer_copy_clipboard()

821gtk_text_buffer_create_tag() 820gtk_text_buffer_cut_clipboard()

821gtk_text_buffer_delete_selection()

821gtk_text_buffer_get_bounds()

832gtk_text_buffer_get_end_iter()

832gtk_text_buffer_get_selection_

bounds() 821gtk_text_buffer_get_text() 832gtk_text_buffer_insert() 832gtk_text_buffer_paste_clipboard()

821gtk_text_view_get_buffer() 820gtk_toolbar_append_space() 806gtk_toolbar_insert_stock() 806GTK_TYPE_ACCEL_GROUP 804GTK_TYPE_ADJUSTMENT 785,

794Signale 795

GTK_TYPE_BUTTON 777Eigenschaften 783

GTK_TYPE_CHECK_BUTTON 777Eigenschaften 783–784

GTK_TYPE_CLIPBOARD 813GTK_TYPE_COMBO

Eigenschaften 809GTK_TYPE_ENTRY 785, 791

Eigenschaften 791GTK_TYPE_FILE_SELECTION

Eigenschaften 832GTK_TYPE_HBOX 765

Eigenschaften 766GTK_TYPE_HBUTTON_BOX 772GTK_TYPE_HPANED 767, 770

Eigenschaften 770

Page 105: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1232

GTK_TYPE_HSCALE 792Eigenschaften 792Signale 793

GTK_TYPE_HSEPARATOR 763GTK_TYPE_IMAGE 764GTK_TYPE_LABEL

Eigenschaften 760GTK_TYPE_MENU 808GTK_TYPE_NOTEBOOK 767,

771Eigenschaften 772

GTK_TYPE_OPTION_MENU 808GTK_TYPE_PROGRESS_BAR 765GTK_TYPE_RADIO_BUTTON

777, 783Eigenschaften 783–784

GTK_TYPE_RANGE 792GTK_TYPE_SCROLLED_

WINDOW 823Eigenschaften 823

GTK_TYPE_SPIN_BUTTON 785, 793Eigenschaften 793

GTK_TYPE_TABLE 773–774Eigenschaften 776

GTK_TYPE_TEXT_BUFFER 813GTK_TYPE_TEXT_ITER 813GTK_TYPE_TEXT_MARK 813GTK_TYPE_TEXT_TAG 813GTK_TYPE_TEXT_TAG_TABLE

813GTK_TYPE_TEXT_VIEW 813, 820GTK_TYPE_TOGGLED_BUTTON

777Eigenschaften 783–784

GTK_TYPE_TOOLBAR 795, 805Eigenschaften 805

GTK_TYPE_TOOLTIP 806GTK_TYPE_VBOX 765

Eigenschaften 766GTK_TYPE_VBUTTON_BOX 772GTK_TYPE_VPANED 767, 770

Eigenschaften 770GTK_TYPE_VSCALE 785, 792

Eigenschaften 792Signale 793

GTK_TYPE_VSEPARATOR 763GTK_TYPE_WINDOW 750, 752

Eigenschaften 752gtk_widget_add_accelerator()

804gtk_widget_destroy() 748

gtk_widget_hide() 748gtk_widget_hide_all() 748gtk_widget_set_event() 835gtk_widget_show() 748gtk_widget_show_all() 748gtk_window_add_accel_group()

804GtkAccelGroup 804GtkAdjustment 785, 794GtkBox 765GtkButton 777, 784GtkCellRenderer 838GtkCellRendererPixbuf 838GtkCellRendererText 838GtkCellRendererToggle 838GtkCheckButton 784GtkCheckButtons 777GtkClipboard 813, 839GtkColorSelection 824GtkCombo 808GtkDialog 753GtkEditable 795GtkEntry 785, 791, 793, 795, 808GtkFileSelection 824, 831GtkFontSelection 824GtkHBox 765GtkHButtonBox 772GtkHPaned 767, 770GtkHScale 785, 792GtkImage 758, 764GtkItemFactory 795, 800GtkItemFactoryEntry 800GtkItemFactoryEntry-Struktur

800GtkLabel 758, 760, 805GtkListStore 838GtkMenu 795, 808GtkMenuBar 795GtkMessageDialog 757, 807GtkNotebook 767, 771GtkOptionsMenu 808GtkProgressBar 765GtkRadioButton 777, 783–784GtkRange 792GtkRuler 839GtkScale 785GtkScrolledWindow 823GtkSeparator 758, 763GtkSpinButton 785, 793GtkStatusbar 758GtkTable 773–774GtkTextBuffer 813, 820

GtkTextIter 813GtkTextMark 813GtkTextTag 813GtkTextTagTable 813GtkTextView 813, 820GtkToggleButton 777, 784GtkToolbar 805GtkTooltip 806GtkTreeModel 838GtkTreeStore 838GtkTreeView 838GtkTreeViewColumn 838GtkVBox 765GtkVButtonBox 772GtkVPaned 767, 770GtkVScale 785, 792GtkWindow 750, 752–753, 807gunzip 1195gzip 1195

H

Halbgrafik 679halfdelay() 687halt 1203has_colors() 696head 1160herror() 441High Level 44Hintergrundprozess 249, 956

Hervorholen 1058hline() 701höhere Ebene 44host 1210Host Byte Order 425HOST_NOT_FOUND 441hostname 1206HP-UX 30–31htonl() 425, 1138htons() 425, 1138HTTP 414HTTPS 414hypot() 1111

I

I18n 39id 1170IEEE 37if

Shell 1006ifconfig 1207

Page 106: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1233

IFSShellvariable 1035

IFTODT() 99inet_addr() 432inet_aton() 426, 432, 1139inet_lnaof() 435, 1139inet_makeaddr() 435, 1139inet_netof() 435, 1139inet_network() 434, 1139inet_ntoa() 433, 1139inet_ntop() 434, 1140inet_pton() 433, 1139info 1219init 242init_pair() 697initscr() 680init-Skript 242Inline-Eingabeumleitung 1033Inode, ermitteln 120INT_MAX 1091INT_MIN 1091Integer-Arithmetik

Shell 979Integertypen 1109Interprozesskommunikation 275

Benannte Pipes 303Benannte Pipes (FIFO-Pipe) 277FIFO-Pipes 303Lock Files 281Message Queue 278, 328Namenlose Pipe 276Namenlose Pipes 283Pipes 283Record Locking 281Semaphoren 279, 321Shared Memory 279, 339Sockets 281STREAMS 280System V IPC 318Unix-Domain-Sockets 496

inttypes 1109ioctl() 78, 151IP_ADD_MEMBERSHIP 488, 503IP_DROP_MEMBERSHIP 488,

503IP_HDRINCL 487IP_MULTCAST_IF 503IP_MULTICAST_IF 488IP_MULTICAST_LOOP 488, 504IP_MULTICAST_TTL 488, 504IP_OPTIONS 487IP_RECVDSTADDR 487

IP_RECVIF 487IP_TOS 487IP_TTL 487IPC_CREAT 324, 329, 340IPC_EXCL 324, 329, 340IPC_INFO 326, 331, 340IPC_PRIVATE 324, 329, 340IPC_RMD 331IPC_RMID 326, 340IPC_SET 326, 331, 340IPC_STAT 326, 331, 340IPv4 514

Portieren nach IPv6 515IPv6 514–515IPV6_ADD_MEMBERSHIP 488IPV6_ADDRFORM 488IPV6_CHECKSUM 488IPV6_DROP_MEMBERSHIP 488IPV6_DSTOPTS 488IPV6_HOPLIMIT 488IPV6_HOPOPTS 488IPV6_MULTICAST_HOPS 488IPV6_MULTICAST_IF 488IPV6_MULTICAST_LOOP 488IPV6_NEXTHOP 488IPV6_PKTINFO 488IPV6_PKTOPTIONS 488is_wintouched() 702isalnum() 1088isalpha() 1088isascii() 1088isatty() 669iscntrl() 1088isdigit() 1088isgraph() 1088islower() 1088iso646 1105isprint() 1088ispunct() 1088isspace() 1088isupper() 1088isxdigit() 1088

J

jmp_buf 1095jobs 1174

Shell 1059Jobverwaltung 249

bg 250fg 250Shell 1059

K

Keep Alive 480Kernelinformationen 139Kernel-Level 44keypad() 682kill 1174

Shell 1054kill() 256, 267, 1129killall 1174Kommando

adduser 1172afio 1190alias 1221apropos 1219arp 1206at 1173badblocks 1180basename 1168batch 1173bc 982, 1221bg 1060, 1174bunzip2 1190bzcat 1151bzip2 1190cal 1202cat 1151cd 1168cfdisk 1181chgrp 1152chmod 1153chown 1154cksum 1152clear 1217cmp 1154comm 1154compress 1190cp 1155cpio 1190cron 1174crypt 1193csplit 1156cut 984, 1156date 1202dd 1181dd_rescue 1183df 1179diff 1156diff3 1157dig 1210dircmp 1168dirname 1168

Page 107: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1234

Kommando (Forts.)dmesg 1203dos2unix 1157Drucker- 1205du 1179dump 1193dumpe2fs 1183e2fsck 1184echo 1028env 1221exec 1043exit 1169expand 1158export 991fdformat 1184fdisk 1185fg 1058, 1174file 1158find 1159finger 1169fold 1159free 1180fsck 1186getopts 1004groupadd 1170groupdel 1170groupmod 1170groups 1170gunzip 1195gzip 1195halt 1203head 1160host 1210hostname 1206id 1170ifconfig 1207info 1219jobs 1059, 1174kill 1054, 1174killall 1174last 1170less 1160let 980ln 1161logname 1171logout 1169ls 1161mail 1208mailx 1208man 1219md5 1152md5sum 1152

Kommando (Forts.)mesg 1216mkdir 1168mkfs 1187mknod 1046mkswap 1187more 1161mount 1188mt 1196mv 1161netstat 1209newgrp 1171nice 1175nl 1162nohup 1175nslookup 1210od 1162pack 1197parted 1189passwd 1171paste 985, 1163pcat 1163pgrep 1176ping 1210Postscript 1221printenv 1221printf 1030prtvtoc 1189ps 1175pstree 1176pwd 975, 1169rcp 1211read 1031reboot 1204renice 1176reset 1217restore 1193r-Kommandos 1211rlogin 1211rm 1163rmdir 1169rsh 1211rsync 1214rwho 1211scp 1213set 1003setterm 1217shift 1002shutdown 1204sleep 1177sort 1163split 1164

Kommando (Forts.)ssh 1212ssh-keygen 1213stty 1217su 1177sudo 1178sum 1152swap 1180swapoff 1189swapon 1189sync 1189tac 1164tail 1047, 1165tar 1197tee 970, 1165test 1011time 1178top 1178touch 1165tr 986, 1166traceroute 1215trap 1055tty 1218type 1166typeset 980ufsdump 1193ufsrestore 1193umask 1166umount 1188unalias 1221uname 1203uncompress 1190uniq 1167unix2dos 1167unpack 1197unzip 1201uptime 1203useradd 1172userdel 1172usermod 1172uudecode 1209uuencode 1209wait 1058wall 1216wc 1167whatis 1220whereis 1167who 1172whoami 1172write 1216zcat 1168zip 1201

Page 108: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1235

Kommando (Forts.)zless 1168zmore 1168

Kommandoausführung überprüfenShell 1007

Kommandosubstitution 998Kommandozeilenargument

Shell 999Kommandozeilenoptionen

auswertenShell 1004

KommunikationsmodellSocket 415

Korn-Shell 954ksh 954

L

L_ctermid 666L10N 39labs() 1101Large Files System 58last 1170lchown() 1124lconv-Struktur 1093LDBL_DIG 1090LDBL_EPSILON 1091LDBL_MANT_DIG 1090LDBL_MAX 1091LDBL_MAX_10_EXP 1090LDBL_MAX_EXP 1090LDBL_MIN 1091LDBL_MIN_10_EXP 1090LDBL_MIN_EXP 1090ldconfig 884ldiv() 1101less 1160let 980LEX 949libpq-fe 1146limits 47, 1091, 1112Link 120

abfragen 122dangling symlink 121Hart 121Symbolisch 121

link() 121LINK_MAX 1113Linker 860Linux 32

Geschichte 32

Linux (Forts.)Torvald 32

listen() 421, 1136Listing

add_db.c 597addr.c 435admin.c 595backward.c 58, 127baud.c 668cdrom.c 163child.c 212child2.c 214child3.c 215child4.c 217client.c (FIFO-Pipes) 315client.c (Multicast) 505client.c (TCP) 426client.c (TCP/linear) 451client.c (UDP) 494client_msq.c 336client_shm.c 346cpy_file.c 56cpy_file_mmap.c 1118cur1.c 681cur10.c 694cur11.c 698cur12.c 703cur13.c 708cur14.c 709cur15.c 710cur2.c 683cur3.c 685cur4.c 686cur5.c 688cur6.c 690cur7.c 691cur8.c 692cur9.c 693daemon.c 239dup_fd.c 60dynamisch.c 887environ1.c 200environ2.c 201eventloop1.c 193eventloop2.c 194exec_child.c 230exec1.c 227exec2.c 228exec3.c 228exec4.c 229exec5.c 229exec6.c 229

Listing (Forts.)fifo_buf.c 309fifo1.c 306fifo2.c 307fifo4.c 309file_size.c 124file_times.c 125filetest.c 113filetest2.c 113filter.c 292find_dir.c 107ftwalk.c 110get_env.c 201glib1.c 722glib2.c 724glib3.c 725glib4.c 728glib5.c 730glib6.c 733glib7.c 735glib8.c 737gtk1.c 750gtk1b.c 753gtk2.c 758gtk2b.c 762gtk3.c 767gtk3b.c 773gtk4.c 777gtk5.c 785gtk6.c 795gtk6b.c 809gtk7.c 813gtk8.c 824gtk9.c 836index_news.c 600kernelinf.c 141key_ftok.c 319keystroke.c 661list_wd.c 101logging.c 237login.c 592Login.html 590make_file.c 49memory.c 130, 942msq_header.h 332my_cgi.h 584my_eof.c 658my_find.c 232my_getch.c 663my_getpass.c 659my_getpid.c 137my_limit.c 208

Page 109: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1236

Listing (Forts.)my_link.c 122my_programm.c 230my_setlocale.c 1092my_stat.c 117my_tty.c 666mychdir.c 96myequal.c 881myequal.h 881myinfo.c 133mymkdir.c 94mysql1.c 551mysql2.c 552mysql3.c 556mysql4.c 566non_block.c 510offsetof() 1097openCD.c 78ping_pong.c 266pipe1.c 285pipe2.c 288pipe3.c 290pipe3b.c 293play_fd.c 64poll_stdin_time.c 76polling_fifo.c 312popen1.c 295popen2.c 297postgre1.c 636postgre3.c 639, 645printme.c 300printme2.c 301prio.c 192prio_child.c 219proz_dat.c 210pserver.c (TCP/parallel) 455put_env.c 202put_env2.c 203reverse.c 615scan_dir.c 105search_db.c 603sem.c 322sende.c 666sender.c 313server.c (FIFO-Pipes) 316server.c (Multicast) 504server.c (TCP) 429server.c (TCP/linear) 449server.c (UDP) 492server_msq.c 334server_shm.c 344set_env.c 204

Listing (Forts.)setbaud.c 669shm_header.h 342sig.c 262sig_sync.c 271sperre.c 72strxcat.c 1096summe.c 616terminfo.c 674terminfo2.c 677testlist.c 882thserver.c (TCP/Thread) 482trash.c 66ugid.c 119unset_env.c 205waise.c 220wait.c 223waitpid.c 226write_file.c 52write_vec.c 79zombie.c 221

Little Endian 425ln 1161locale 1091localeconv() 1093localtime() 1104Lock Files 281lockf() 67, 74log() 1094LOG_ALERT 234LOG_AUTH 234LOG_AUTHPRIV 234LOG_CONS 235LOG_CRIT 234LOG_CRON 235LOG_DAEMON 234LOG_DEBUG 234LOG_EMERG 234LOG_ERR 234LOG_FTP 234LOG_INFO 234LOG_KERN 234LOG_LOCAL0 235LOG_LPR 234LOG_MAIL 234LOG_NDELAY 235LOG_NEWS 234LOG_NOTICE 234LOG_PERROR 235LOG_PID 235LOG_SYSLOG 234LOG_USER 234

LOG_UUCP 234LOG_WARNING 234log10() 1094log2() 1110logb() 1110Logischer Operator

Shell 1017logname 1171logout 1169LONG_MAX 1091LONG_MIN 1091longjmp() 1095Low Level 43ls 1161lseek() 57, 1114lstat() 115, 1123

M

mail 1208mailx 1208MAKE 866

Abhängigkeit 870Abkürzungen 874Implizite Regeln 876Installieren von Anwendungen

878Kommentare 869Makefile 868Makros 874Makros (Übersicht) 875Musterregeln 878TAbulator 869Variablen 875Ziel (target) 869

Makefile 868malloc() 1101man 1219Mandatory Locking 68, 74

mit Linux 68math 1094, 1110Mausprogrammierung 706MAX_CANON 1113MAX_INPUT 1113MB_LEN_MAX 1091md5 1152md5sum 1152memchr() 1102memcmp() 1102memcpy() 1102memlockall() 1120memmove() 1102

Page 110: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1237

Memory Leaks 942efence 942valgrind 945

Memory Mapped Ein/Ausgabe 1115

memset() 1102Mesa 3D 854mesg 1216Message Queue 278, 328

Ändern 331Erfragen 331Erzeugen 329Löschen 331Nachricht empfangen 330Nachricht versenden 329Öffnen 329struct msqid_ds 331

mkdir 1168mkdir() 94, 1121mkfifo 1046mkfifo() 305, 1130mkfs 1187mknod 1046mknod() 308mkstemp() 93mkswap 1187mktemp() 93mktime() 1104mlock() 1120mmap() 1116modf() 1094more 1161mount 1188mouseinterval() 709mousemask() 706move() 686MSG_WAITALL 446msgctl() 331, 1130msgget() 329, 1130msgrcv() 330, 1130msgsnd() 329, 1130msync() 1118mt 1196Multicast-Socket 502

Anwendungsgebiete 509Multiplexing 75, 1114Multiplexing I/O 462munlock() 1120munlockall() 1120munmap() 1117Mutexe 370mv 1161

mvdelch() 690mvgetch() 682mvgetnstr() 685mvgetstr() 685mvprintw() 686mvwin() 702mvwprintw() 700my_ulonglong 1146MYSQL 1145MySQL 522

Anwendungsgebiete 523Autowerte definieren 538Benutzer entfernen 528Benutzer hinzufügen 528Daten ändern 541Daten ausgeben 543Daten einfügen 541Daten importieren 542Daten löschen 542Datenbank anlegen 534Datenbank löschen 534Datenbank verwenden 534Datentypen 531DDL-Befehle 531DML-Befehle 531Grafische Clients 530Indicies 537Installation 524Kommandozeilenwerkzeuge 526Konfigurationsdatei 525my.cnf 525mysql (Client) 527mysqladmin 527MySQLCC 530mysqldump 529mysqlshow 529NULL 545Passwort einrichten 528phpMyAdmin 530Schlüsselfelder 536Schnittstellen 524Server starten/stoppen 524Tabelle ändern 538Tabelle anlegen 535Tabelle umbenennen 538Tabellentypen 538UDF-Schnittstelle 610Unscharfe Suche 545

MySQL C-API 546Benutzer wechseln 577Datenbanknamen abfragen 559Ergebnismenge 572

MySQL C-API (Forts.)Ergebnissmenge bearbeiten 560Fehlerbehandlung 549Fehlercodes 549Feldcursor abfragen 565Feldcursor platzieren 565Informationen abfragen 555my_ulonglong 561MYSQL_FIELD 562MYSQL_FIELD_OFFSET 565MYSQL_RES 558MYSQL_ROW 560MYSQL-Objekt initialisieren 547Server-Threads ermitteln 559Spaltenweise abarbeiten 562SQL-Befehle an den Server 573Tabellennamen abfragen 559Veraltete Funktionen 582Verbindung herstellen 548Verbindung schließen 550Weitere Funktionen 577Zeilencursor abfragen 561Zeilencursor platzieren 561Zeilenweise abarbeiten 560Zugangsdaten 583

mysql_affected_rows() 576, 1141mysql_change_user() 577, 1142mysql_character_set_name()

1142mysql_close() 550, 1141mysql_connect() 549, 1141mysql_create_db() 1142mysql_data_seek() 572, 1142mysql_debug() 582, 1142mysql_drop_db() 1142mysql_dump_debug_info() 582,

1142mysql_eof() 1142mysql_errno() 549–550, 1142mysql_error() 550, 1142mysql_escape_string() 578, 1142mysql_fetch_field() 564, 1142mysql_fetch_field_direct() 564,

1143mysql_fetch_fields() 564mysql_fetch_lengths() 573mysql_fetch_row() 560, 1143MYSQL_FIELD 1146mysql_field_count() 565, 1143MYSQL_FIELD_OFFSET 1146mysql_field_seek() 565, 1143mysql_field_tell() 565, 1143

Page 111: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1238

mysql_free_result() 559, 577, 1143

mysql_get_client_info() 555, 1143

mysql_get_host_info() 555, 1143mysql_get_proto_info() 555,

1143mysql_get_server_info() 556,

1143mysql_info() 556, 1143mysql_init() 547, 1143mysql_insert_id() 578, 1143mysql_kill() 1144mysql_list_dbs() 559, 1144mysql_list_fields() 559, 1144mysql_list_processes() 559, 1144mysql_list_tables() 1144mysql_num_fields() 560, 566,

1144mysql_num_rows() 561, 1144mysql_options() 579, 1144mysql_ping() 580, 1144mysql_query() 573, 1144mysql_real_connect() 548–549,

1144mysql_real_escape_string() 578,

1142mysql_real_query() 573, 1145mysql_reload() 1145MYSQL_RES 1145MYSQL_ROW 1145MYSQL_ROW_OFFSET 561mysql_row_seek() 561, 1145mysql_row_tell() 561, 1145mysql_select_db() 581, 1145mysql_shutdown() 581, 1145mysql_stat() 1145mysql_store_result() 565, 574,

1145mysql_thread_id() 581, 1145mysql_thread_safe() 1145mysql_use_result() 575, 1145MySQL-Befehl

ALTER TABLE 539Benutzerdefinierte Funktionen

615CREATE DATABASE 534CREATE FUNCTION 618CREATE TABLE 535DELETE 542DROP DATABASE 535DROP FUNCTION 618

MySQL-Befehl (Forts.)Eigene Funktionen schreiben 609Erweitern in C 609EXPLAIN 538GRANT 528INSERT INTO 541LOAD DATA INFILE 542MODIFY 540REVOKE 528SELECT 543SHOW DATABASES 534UPDATE 541USE 535

N

NAME_MAX 1113Named Pipes

Shell 1046Namen Server 439Namen-Expansion

Shell 972nanosleep() 269, 1129ncurses

ACS_-Sonderzeichen 686Ausgabe 685Beenden 680Bildschirm ab Cursor löschen

690Bildschirm löschen 690Cursor positionieren 686Cursortasten 684Eingabe 682Farbe 696Farbenpaar 697Fenster als Verändert markieren

702Fenster duplizieren 701Fenster freigeben 701Fenster verschieben 702Fenstereigenschaften 691Fenstergröße ermitteln 702Fensterinhalt kopieren 703Fensterroutinen 700Funktionstasten 684Initialisieren 680Linie zeichnen 701Mausprogrammierung 706Position des Cursors ermitteln

693Rahmen zeichnen 701raw-Modus 682

ncurses (Forts.)Schriftattribute 696Scrolling 691, 693Sonderzeichen 687String ausgeben 689String einlesen 684Tastaturmodus 681Weitere Fenster 701y/x-Bezugspunkt ermitteln 702Zeichen am Cursor löschen 690Zeichen ausgeben 687Zeile ab Cursor löschen 690Zeile einfügen 686Zeile löschen 686

ncurses-Bibliothek 679netdb 1140netinet 1138netstat 1209Network Byte Order 425Netzwerkprogrammierung 407

Adressfamilie 416Big-Endian 425Clientanwendung 424Clientanwendung (UDP) 491Daten empfangen 422, 492Daten senden 422, 492Datenformat 461Host Byte Order 425IPv4 514IPv4 nach IPv6 515IPv6 514Konverter-Funktionen 432Little-Endian 425Multicast-Socket 502Network Byte Order 425Nichtblockierende Socket 509Parallele Server 448Protokollfamilie 416Pufferung 446Raw Socket 512RPC 513Serveranwendung 427Serveranwendung (UDP) 492Sicherheit 517Socket 414Socket an Port binden 420Socket anlegen 416Socket-Optionen 485Socketschnittstelle 416Socket-Typen 417Systemabhängiges 425Threads 481

Page 112: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1239

Netzwerkprogrammierung (Forts.)TLI 513UDP 489Verbindung schließen 423Verbindungsaufbau (Client) 418Verbindungswünsche abarbeiten

421Verschlüsselung 517Warten auf Verbindung 421XTI 513

NetzwerktechnikAnwendungsschicht 409Bitübertragungsschicht 408DNS 411Internet (www) 410Kommunikationsmodell 415Kommunikationsschicht 409Netzklasse 434Netzwerknummer 434Ports 413Präsentationsschicht 409Protokolle 413Refernzmodell 408RFC 413Sicherungsschicht 409TCP/IP 411TCP/IP-Schichtenmodell 409Transportschicht 409Vermittlungsschicht 409

newgrp 1171newwin() 701nftw() 1122NGROUPS_MAX 1113nice 1175Nichtblockierende Socket 509NIS 184nl 1162NLS 39NO_ADDRESS 441NO_DATA 441NO_RECOVERY 441nocbreak() 681noecho() 682nohup 1175noraw() 682nslookup 1210ntohl() 425, 1138ntohs() 425, 1138NTP 414

O

O_ACCMODE 63O_APPEND 47–48, 57O_ASYNC 54, 63O_CREAT 48, 51O_EXCL 48O_LARGEFILE 58O_NDELAY 287O_NOCTTY 48O_NONBLOCK 48, 75, 287, 308O_RDONLY 47O_RDWR 47O_SYNC 48, 54, 81O_TRUNC 48, 51, 82O_WRONLY 47od 1162off_t 58offsetof() 1097open() 46, 1114OPEN_MAX 47, 52, 76, 1113opendir() 100, 1121OpenGL 854openlog() 235OSI-Schichtenmodell 408overlay() 703overwrite() 703

P

pack 1197pair_content() 698Pango 761parted 1189PASS_MAX 1113passwd 169, 1171

Struktur 170Passwortdatei 169, 174paste 1163

Shell 985PATCH 949PATH_MAX 1113pause() 260, 268, 1129pcat 1163pclose() 1129pdksh 954perror() 47, 1100PF_APPLETALK 417PF_ATMPVC 417PF_AX25 417PF_INET 416PF_INET6 416

PF_IPX 416PF_LOCAL 416PF_NETLINK 416PF_PACKET 417PF_UNIX 416PF_X25 417pgrep 1176PID 189PID_MAX 1113ping 1210Pipe

Shell 969Pipe (benannt) 277pipe() 283, 1129PIPE_BUF 291, 308, 1113Pipes 283

Drucken mit lpr 299Eigenschaften 283elementare Ein-/Ausgabe 287Filterprogramm 292Mail versenden 296Standard Ein-/Ausgabe 287Umleiten 289

Pipes (benannt) 303Pipes (namenlos) 276PIPESTATUS

Shell 1008POP3 414popen() 295, 1079, 1129Position des Cursors ermitteln

693Positionsparameter

Shell 1000POSIX 37POSIX_CHOWN_RESTRICTED

1113POSIX_JOB_CONTROL 1113POSIX_NO_TRUNC 1113POSIX_PRIORITY_SCHEDULING

194POSIX_SAVED_IDS 1113POSIX_SOURCE 1113POSIX_VERSION 1113PostgreSQL 619

.pgpass 651Benutzerverwaltung 623Daten ausgeben 629Daten hinzufügen 628Datenbank verwenden 626Datentypen 624Grafische Frontends 627im Vergleich mit MySQL 619

Page 113: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1240

PostgreSQL (Forts.)Installieren 621Konfigurationsdateien 622Passwortdatei 651pg_hba.conf 622phpPgAdmin 627postgresql.conf 622Server starten/stoppen 624Syntax 620Tabelle anlegen 628Tabelle löschen 628Umgebungsvariablen 651Unscharfe Suche 630

PostgreSQL C-API 631Anfrage an den Server 637Anwendung übersetzen 631Ergebniss einer Anfrage 638Fehlerbehandlung 634Informationen zur Verbindung

633NULL 643Rückgabe einer Anfrage auslesen

642Status der Verbindung 633Status einer Anfrage 638Statuszeichenkette einer Anfrage

ermitteln 644Threads 652Verbindung herstellen 632Verbindung schließen 635Verbindung wiederaufnehmen

635PostgreSQL-Befehl

CREATE TABLE 628DELETE FROM 629DROP TABLE 628INSERT INTO 628SELECT 629UPDATE 629

Postscript-Kommandos 1221pow() 1095PPID 189PQbackendPID() 635, 1147PQbinaryTuples() 639, 1148PQclear() 639, 1148PQcmdStatus() 644, 1149PQcmdTuples() 644, 1149PQconnectdb() 632, 1146PQconnectPoll() 632, 1146PQconnectStart() 632, 1146PQdb() 635, 1147PQerrorMessage() 634

PQexec() 637, 1148PQfinish() 635, 1147PQfmod() 639, 1148PQfname() 638, 1148PQfnumber() 639, 1148PQfsize() 639, 1148PQftype() 639, 1148PQgetisnull() 643, 1149PQgetlength() 643, 1149PQgetssl() 635, 1147PQgetvalue() 643, 1149PQhost() 635, 1147PQnfields() 638, 1148PQntuples() 638, 1148PQoidStatus() 644, 1149PQoidValue() 644, 1149PQoptions() 635, 1147PQpass() 635, 1147PQport() 635, 1147PQreset() 635, 1147PQresetPoll() 636, 1147PQresetStart() 636, 1147PQresStatus() 638, 1148PQresultErrorMessage() 638,

1148PQresultStatus() 638, 1148PQsetdb() 632, 1146PQsetdbLogin() 632, 1146PQsocket() 635, 1147PQstatus 633PQstatus() 1147PQtty() 635, 1147PQuser() 635, 1147Präprozessor 859printenv 1221printf

Shell 1030printf() 86, 1099proc 129, 131–133, 135–140,

145–146Profiling 865, 923

Laufzeit einzelner Codezeilen 927

Laufzeit von Funktionen 924Laufzeit von Prozessen 923

Prozess 187Adressraum 188Ausführung 242Auslagerung 195Benutzernummer (UID, EUID)

189cron-Job 252

Prozess (Forts.)Daemon 242Dämon- 232Deadlocks 282Eltern- 211Erzeugung 211Flusskontrolle 282Gruppennummer (GID, EGID)

189Hintergrund 249init 199, 242init-Skript 242Jobverwaltung 249Kenndaten 188Kind- 211Kind überlagern 230Kommando

ps 196Komplett ersetzen 226Lebenszyklus 198Limits 206Parallele Server (TCP) 448Priorität 191Priorität verändern 218Prozesserkennung 209Prozessnummer (PID) 189Prozessnummer des Vaters (PPID)

189Pufferung 214Race Condition 282Runlevel 242Scheduling-Priorität abfragen

192Scheduling-Priorität verändern

192Startup-Skripte 244Status 190Steuerterminal 195Stoppen 268, 270Stoppen (Zeit) 269Suspendieren 268, 270Suspendieren (Zeit) 269Swapping 195Synchronisieren (Signale) 271Timesharing 191Überwachen 196Umgebungsvariablen 200Vererbung 218Verhungern 282Warten 220Warteschleife 193Zeitgesteuert ausführen 252

Page 114: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1241

Prozess (Forts.)Zombie 199Zugriffsdisziplinen 282Zustände 190

ProzesseSignale 257

Prozesstabelleneintrag 45, 256prtctoc 1189ps 1175pstree 1176pthread 1132pthread_attr_destroy() 362, 1133pthread_attr_getdetachestate()

362pthread_attr_getdetachstate()

1133pthread_attr_getinheritsched()

367, 1133pthread_attr_getschedparam()

367pthread_attr_getschedpolicy()

367, 1133pthread_attr_init() 362, 1133pthread_attr_setdetachestate()

362pthread_attr_setdetachstate()

1133pthread_attr_setinheritsched()

367, 1133pthread_attr_setschedparam()

367pthread_attr_setschedpolicy()

366, 1133pthread_cancel() 391, 1135PTHREAD_CANCEL_ASYNCHRO

NOUS 391PTHREAD_CANCEL_DEFERRED

391PTHREAD_CANCEL_DISABLE

391pthread_cleanup_pop() 354pthread_cleanup_push() 354pthread_cond_broadcast() 378,

1135pthread_cond_destroy() 382,

1135pthread_cond_init() 382, 1135PTHREAD_COND_INITIALIZER

378pthread_cond_signal() 378, 1135pthread_cond_timedwait() 378pthread_cond_timewait() 1135

pthread_cond_wait() 378, 1135pthread_condattr_destroy() 387pthread_condattr_init() 387pthread_create() 352, 1132PTHREAD_CREATE_DETACHED

362–363PTHREAD_CREATE_JOINABLE

362pthread_detach() 361, 1132pthread_equal() 359, 1132pthread_exit() 353, 1132PTHREAD_EXPLICIT_SCHED 367pthread_getschedparam() 364pthread_getspecific() 396PTHREAD_INHERIT_SCHED 367pthread_join() 354, 1132pthread_key_create() 396pthread_key_delete() 396pthread_kill() 401pthread_mutex_destroy() 374,

1134PTHREAD_MUTEX_

ERRORCHECK_NP 377PTHREAD_MUTEX_FAST_NP

377pthread_mutex_init() 374PTHREAD_MUTEX_INITIALIZER

371pthread_mutex_lock() 371,

1133–1134PTHREAD_MUTEX_

RECURSIVE_NP 377pthread_mutex_trylock() 371,

1134pthread_mutex_unlock() 371,

1134pthread_mutexattr_destroy()

377, 1134pthread_mutexattr_getkind_np()

1134pthread_mutexattr_gettype()

377, 1134pthread_mutexattr_init() 377,

1134pthread_mutexattr_setkind_np()

1134pthread_mutexattr_settype() 377,

1134pthread_once() 398PTHREAD_ONCE_INIT 399pthread_self() 354, 1132

pthread_setcancelstate() 391, 1135

pthread_setcanceltype() 391, 1135

pthread_setschedparam() 364pthread_setspecific() 396pthread_sigmask() 401pthread_testcancel() 391ptrintw() 686Puffer 54–55Puffer kontrollieren 91Puffereinstellung

ANSI C 92SVR4 92

Pufferüberlauf 942, 1071putc() 88, 1099putchar() 88, 1099putenv() 202, 1125putp() 677puts() 88, 1100pwd 975, 1169pwd.h 170

Q

qsort() 1102Qt 849Qt-Designer 851Quotings

Shell 997

R

Race Condition 282, 1073raise() 256, 267, 1129rand() 1101ranlib 882Raw Socket 512raw() 682rcp 1211RCS 898–899

Auschecken 902Auschecken (read-only) 903Auschecken älterer Version 904Einchecken 902Konzept 900rcsdiff 907Revisionsnummer erzwingen

905Revisonsnummer verändern 905Schlüsselwörter 907Versionen vergleichen 907

Page 115: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1242

RCS (Forts.)Versionsbäume 901Versionsprotokoll (rlog) 905Zugriffsliste 906

readShell 1031

read() 55, 287, 422, 1114readdir() 100, 1121readdir_r() 103readlink() 122readv() 79realloc() 1101reboot 1204Record Locking 66, 281

exclusiv locks 67shared locks 67

recv() 423, 1137recvfrom() 492, 1137Referenz 1087refresh() 686, 691regcomp() 106regerror() 106regex 106regex_t 106regexec() 106regfree() 106remove() 92, 1098rename() 92, 1098renice 1176reset 1217Ressourcenlimits 206restore 1193rewind() 90, 1100rewinddir() 103, 1121RFC 413rint() 1110r-Kommandos 1211RLIM_INFINITY 206RLIMIT_CORE 207RLIMIT_CPU 207RLIMIT_DATA 207RLIMIT_FSIZE 207RLIMIT_LOCKS 207RLIMIT_MEMLOCK 207RLIMIT_NOFILE 207RLIMIT_NPROC 207RLIMIT_RSS 207RLIMIT_STACK 207rlogin 1211rm 1163rmdir 1169rmdir() 93, 97, 1121

round() 1110RPC 513RPM 888

Benötigte Komponenten 890Build-Abschnitt 894Einführung 889Files-Sektion 894Install-Abschnitt 894Präambel 892Paket erstellen 895Paket installieren 897Patches 890Prep-Abschnitt 893Sourcecode 890–891Specfile 890, 892Verzeichnisse 890

rsetlimit() 47rsh 1211rsync 1214Runlevel 242rwho 1211

S

S_IRGRP 49, 116, 1123S_IROTH 49, 117, 1123S_IRUSR 48, 116, 1123S_IRWXG 49S_IRWXO 49S_IRWXU 49S_ISBLK() 116, 1123S_ISCHR() 116, 1123S_ISDIR() 116, 1123S_ISFIFO 285, 305S_ISFIFO() 116, 1123S_ISGID 48S_ISLINK() 116, 1123S_ISREG() 116, 1123S_ISSOCK() 116, 1123S_ISUID 48S_ISVTX 48S_IWGRP 49, 117, 1123S_IWOTH 49, 117, 1123S_IWUSR 48, 116, 1123S_IXGRP 49, 117, 1123S_IXOTH 49, 117, 1123S_IXUSR 48, 116, 1123SA_NOCLDSTOP 262SA_NOCLDWAIT 262SA_NODEFER 262SA_NOMASK 262SA_ONESHOT 262

SA_ONSTACK 262SA_RESETHAND 262SA_RESTART 262SA_SIGINFO 262scalb() 1111scandir() 104, 1121scanf() 87, 1099SCHAR_MAX 1091SCHAR_MIN 1091SCHED_FIFO 363SCHED_OTHER 363SCHED_RR 363sched_setpriority() 269sched_yield() 193Schleife

Shell 1022SCM-Systeme 899scp 1213scrl() 694scroll() 693scrollok() 691SDL 852sed 987SEEK_CUR 57, 90SEEK_END 57, 90SEEK_SET 57, 90seekdir() 103, 1121select

Shell 1047select() 75, 269, 463, 1114, 1129

Sicherheit 1085sem_destroy() 388sem_getvalue() 388sem_init() 387sem_post() 387sem_trywait() 387SEM_UNDO 327sem_wait() 387Semaphore

Threads 387Semaphoren 279, 321

Abfragen 325Ändern 325Erstellen 324Lebenszyklus 321Löschen 325Öffnen 324Operationen 326struct sembuf 327Vergleich mit Sperren 328

semctl() 321, 325, 1131semget() 321, 324, 1131

Page 116: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1243

Semigrafik 679semop() 321, 326, 1131send() 423, 1136Sendmail 296sendto() 492, 1137Sequencing 415set

Shell 1003SETALL 326setbuf() 91, 1098setbuffer() 92setegid() 1126setenv() 204, 1125seteuid() 1126setgid() 210, 1125setgrent() 182set-group-ID Bit 48setjmp 1095setjmp() 1095setlinebuf() 92setlocale() 1092setpriority() 192, 218setpwent() 173setregid() 1126setreuid() 1126setrlimit() 207, 1125setscrreg() 692setsid() 238setsockopt() 431, 486, 507, 1137setspent() 176setterm 1217setuid() 210, 1125setupterm() 673set-user-ID Bit 48SETVAL 326setvbuf() 91, 1099sh 953shadow.h 175Shared Libraries 883Shared Memory 279, 339

Abfragen 340Ändern 340Erstellen 339Löschen 340Öffnen 339Segement loslösen 341Segment anbinden 341shmctl() 340

She-Bang-Zeile 959Shell 951

Array 989A-Shell 954

Shell (Forts.)Auf Prozess warten 1058Ausgabe 1028Auto-Variable 995Bash 954Bourne-Shell 953case 1020C-Shell 953dash 954Dateistatus ermitteln 1015Datenstrom umleiten 965Dezimalzahl 979Dezimalzahlen vergleichen 1012Eingabe 1031Einzelnes Zeichen einlesen 1039elif-Anweisung 1010else-Alternative 1010Festlegen 958for-Schleife 1022Funktion 1050if-Anweisung 1006IFS (Shell-Variable) 1035Jobverwaltung 1059Kommandosubstitution 998Kommandozeilenargument 999Korn-Shell 954Leerzeichen 997Logischer Operator 1017Menü mit select 1047Quotings 997Rechnen 982Schleife 1022Signal 1054tcsh 955test 1011Typ 953Umgebungsvariable 994until-Schleife 1026Variable 976Variableninterpolation 977while-Schleife 1025Zeichenkette 984Zeichenketten vergleichen 1014Zeilenumbruch 998Z-Shell 954

Shellprogrammierung 951Shellskript 951

Ausführen 955Beenden 963Datenstrom umleiten 965Im Hintergrund ausführen 956Kommunikation 1061

Shellskript (Forts.)ohne Subshell 957She-Bang-Zeile 959Subshell 956synchronisieren 1063Variable 976

shiftShell 1002

SHM_LOCK 340SHM_UNLOCK 340shmat() 341, 1131shmctl() 1131shmdt() 1131shmget() 339, 1131SHMMAX 340SHMMIN 340SHRT_MAX 1091SHRT_MIN 1091shutdown 1204shutdown() 1137Sicherheit 1067

Ausführrecht 1071chroot() 1075Core Dump 1082Filedeskriptoren 1080Logfiles 1068popen() 1079Race Condition 1073select() 1085Socketdeskriptoren 1080SQL Injection 1083SUID-Bit 1069Superuser 1068syslog() 1068system() 1079Temporäre Dateien 1074Trojaner 1067Umgebungsvariablen 1076Viren 1067Zugriffsrechte 1069, 1079

sig_atomic_t 265SIG_BLOCK 270, 402SIG_SETMASK 270, 402SIG_UNBLOCK 270, 402sigaction() 261, 1127sigaddset() 261, 1126sigdelset() 261, 1126sigemptyset() 260, 1126SIGEMT 258sigfillset() 260, 1126sighandler_t 261SIGIOT 258

Page 117: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1244

sigismember() 1127SIGKILL 258, 402Signal

Shell 1054signal 1096signal() 1096Signale

Benutzerdefinierte 255Einrichten 261Erfragen 261exec-Aufruf 258fork() 257Gerätesignale 255Neues Signalkonzept 260pending signal 256Prozess suspendieren 270Prozesse synchronisieren 271Senden 267SIGABRT 258SIGALRM 259SIGBUS 258SIGCHLD 199, 257, 259, 454SIGCLD 259SIGCONT 259, 268SIGFPE 258SIGHUP 238, 258SIGILL 256, 258SIGINT 238, 258SIGIO 259SIGLOST 259Signalhandler 265Signalmaske 257, 269Signalmenge 260SIGPIPE 259, 285SIGPOLL 259SIGPROF 259SIGQUIT 258SIGSEGV 256, 258SIGSTOP 257, 259SIGSYS 258SIGTERM 258SIGTRAP 258SIGTSTP 259SIGTTIN 259SIGTTOU 259SIGURG 64, 259SIGUSR1 259, 271SIGUSR2 259, 271SIGVTALRM 259SIGWINCH 238, 259SIGXCPU 259SIGXFSZ 259

Signale (Forts.)Systemsignale 255Threads 401Zeitschaltuhr 268

Signale, SIGFPE 256Signale, SIGIO 64Signalhandler 261Signalmaske

Ändern 269Erfragen 269

SignalmengeHinzufügen 261Initialisieren 260Löschen 261

sigpending() 1127sigprocmask() 269, 1127sigset_t 260SIGSTOP 402sigsuspend() 270, 1127sigtimedwait() 402sigwait() 401sigwaitinfo() 402sin() 1094Single Quotings 997sinh() 1094size_t 52sleep 1177sleep() 269, 1129SMTP 414SNMP 414snprintf() 86SO_BROADCAST 487SO_DEBUG 487SO_DONTROUTE 487SO_ERROR 487SO_KEEPALIVE 487SO_LINGER 487SO_OOBINLINE 487SO_RCVBUF 487SO_RCVTIMEO 487SO_REUSEADDR 487SO_REUSEPORT 487SO_SNDBUF 487SO_SNDTIMEO 487SO_TYPE 487SO_USELOOPBACK 487SOCK_DGRAM 417SOCK_PACKET 417SOCK_RAW 417SOCK_RDM 417SOCK_SEQPACKET 417SOCK_STREAM 417

Socket 414Adressfamilie 416Auf Verbindung warten 421Clientanwendung 424Daten empfangen 422Daten senden 422Kommunikationsmodell 415Lauschen 421Lokale- 500Multicast- 502Multiplexing 462Namen Server 439Nichtblockierend 509Optionen abfragen 485Optionen setzen 485Parallele Server 448Port binden 420Protokollfamilie 416Pufferung 446, 448Raw- 512select() 463Serveranwendung 427sockaddr 420sockaddr_in 419sockaddr_un 497Socket-Deskriptor 418Socket-Typen 417Standard-E/A-Funktionen 447Struktur 419UDP 489Unix-Domain- 496Verbindung schließen 423Verbindungsaufbau (Client) 418Verbindungswünsche abarbeiten

421Webserver 471

socket() 416, 1136Socket-Deskriptor 418socketpair() 500, 1137Sockets 281

Threads 481Solaris 30–31Sonderzeichen 687sort 1163Sperrdateien 281split 1164sprintf() 86, 1099SQL 521SQL Injection 1083sqrt() 1094srand() 1101sscanf() 87, 1099

Page 118: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1245

SSH 414ssh 1212ssh-keygen 1213ssize_t 52Standard E/A-Funktionen

Socket 447Standardausgabe

stdout 45STDOUT_FILENO 45

Standardausgabe umleitenShell 965

Standard-E/A-Funktionen 84Standardeingabe

stdin 45STDIN_FILENO 45

Standardeingabe umleitenShell 968

Standardfehlerausgabestderr 45STDERR_FILENO 45

Standardfehlerausgabe umleitenShell 966

start_color() 697Startup-Skripte erstellen 244stat (Struktur) 115

st_atime 125st_blksize 124st_blocks 124st_ctime 125st_gid 119st_ino 120st_mode 116st_mtime 125st_nlink 120st_size 124st_uid 119

stat() 115, 1123stat-Struktur 1122stdarg 87, 1096stdbool 1109stddef 1097stderr

Shell 966stdin

Shell 968stdint 1109stdio 84, 1098stdlib 1100stdout

Shell 965stdscr 682Steuerterminal 195

sticky Bit 48STRACE 939

Optionen 941strcat() 1103strchr() 1103strcmp() 1103strcoll() 1104strcpy() 1102strcspn() 1103STREAMS 280strerror() 47, 1103strftime() 1104string 1102strlen() 1103strncat() 1103strncmp() 1103strncpy() 1103strpbrk() 1103strrchr() 1103strspn() 1103strstr() 1103strtod() 1100strtok() 1103strtol() 1101strtoll() 1102strtoul() 1101strxfrm() 1104stty 1217su 1177Subshell 956

Explizit verwenden 1060sudo 1178SUID 189SUID-Bit 1069sum 1152Superuser 1068SVR4 39swap 1180swapoff 1189swapon 1189symlink() 121sync 1189Synchronisieren

Shellskripts 1063sys/mman 1116sys/socket 1136sys/stat 115, 1122syslog() 234, 1068System V IPC 318

Gemeinsamkeiten 318ipcrm 324ipcs 323

System V IPC (Forts.)Message Queue 328Semaphoren 321Shared Memory 339

system() 231, 1079, 1101, 1126Systemcalls 43

STRACE 939Systeminformationen 129

T

tac 1164tail 1165

Shell 1047tan() 1094tanh() 1094tar 1197tcgetattr() 657TCP/IP Aufbau 411TCP_KEEPALIVE 489TCP_MAXRT 489TCP_MAXSEG 489TCSADRAIN 657TCSAFLUSH 657TCSANOW 657tcsetattr() 657tcsh 955tee 970, 1165telldir() 103, 1121Telnet 414Temporäre Dateien 1074term 673termcap 672Terminal 653

ANSI-Steuersequenzen 672Attribute 654Ausgabeflags 656Baudrate ermitteln 667Baudrate verändern 669Bildschirm löschen 677curses 679Cursor positionieren 677Eingabeflags 655Escapesequenzen 676Fähigkeiten 672Farbe 696Flags löschen 659Flags setzen 659Geschwindigkeitskontrolle 667Identifizierung 665Kontrollflags 656Lokale Flags 656

Page 119: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1246

Terminal (Forts.)Mausprogrammierung 706Modus 654Pfadname 666raw-Modus 663Semigrafik 679Sonderzeichen 657Sonderzeichen ändern 658Steuerzeichen 661termcap 672terminfo 671termios 653xterm 672

terminfo 671Eigenschaften anwenden 677Eigenschaften eines Terminals

674Escapesequenzen 676Fähigkeiten ermitteln 672Initialisieren 673

termios 653–654termios-Struktur 654test

Shell 1011tgmath 1112Thread-Programmierung 349Threads

Abbrechen 391Attribute 362Barrier 390Bedingungsvariablen 377Beenden 353Bibliotheken 350Canceln 391Conditions Variablen (dynamisch)

382Condition-Variablen 377Condition-Variablen (statisch)

378Condition-Variablen-Attribute

387Daemon- 361Einmaliges Ausführen 398Erzeugen 352Exit-Handler einrichten 353ID ermitteln 354Kernel- 351Loslösen 361Mutex-Attribute 377Mutexe 370Mutexe (dynamisch) 374Mutexe (statisch) 371

Threads (Forts.)Netzwerkprogrammierung 481Prozesse 349Rückgabewert 357RW-Locks 390Scheduling 351, 362Semaphore 387Signale 401Spinlocks 390Synchronisieren 367Thread-safe 400Threadspezifische Daten 395TSD-Daten 395Typen-Casting 357User- 351Vergleichen 359Warten 354Zustände 351

tigetflag() 674tigetnum() 674tigetstr() 674Tilde-Expansion

Shell 975TIME 923time 126, 1104, 1178time() 1104tmpfile() 93, 1098tmpnam() 93, 1098tm-Struktur 1105tolower() 1088Toolkit 715top 1178touch 1165touchwin() 702toupper() 1088tparm() 677tputs() 677tr 1166

Shell 986traceroute 1215trap

Shell 1055Trojaner 1067trunc() 1110truncate() 82TRY_AGAIN 441tty 1218ttyname() 666type 1166typeset

Shell 980

U

UCHAR_MAX 1091UDP 489

Clientanwendung 491Serveranwendung 492

ufsdump 1193ufsrestore 1193UID 189UID_MAX 1113UINT_MAX 1091ulimit() 47ULONG_MAX 1091umask 1166umask() 50, 1124Umgebungsvariable

Shell 994Umgebungsvariablen 200, 1076

Einzeln abfragen 201Hinzufügen 202Löschen 205Verändern 202

umount 1188unalias 1221uname 1203uname() 183uncompress 1190ungetc() 88, 1099ungetch() 685ungetmouse() 713uniq 1167unistd 1113Unix 30

Geschichte 30unix2dos 1167Unix-Domain-Sockets 496unlink() 93unpack 1197unsetenv() 205, 1125until-Schleife

Shell 1026unzip 1201uptime 1203userdel 1172User-ID-Bit 119User-Level 44usermod 1172USHRT_MAX 1091usleep() 269, 1129usr 859UTF-8 749, 831utime() 126

Page 120: Linux-UNIX-Programmierung - filefarmfilefarm.dyndns.org/books/C von A bis Z/content/extra/galileocomputing... · Inhalt 8 6.3.3 getgrent, setgrent und endgrent – alle Einträge

Index

1247

uudecode 1209uuencode 1209

V

va_arg() 1096va_end() 1096va_list 1096va_start() 1096valgrind 945Variable

Auto- (Shell) 995Exportieren 991Shell 976

VariableninterpolationShell 977

vasnprintf() 87vasprintf() 87versionsort() 104Versionsverwaltung 899

CVS 908RCS 899

Verzeichnis 94Arbeitsverzeichnis ermitteln 97Komplett einlesen 104Lesen 100Löschen 97Neu anlegen 94Öffnen 99Positionieren 103Schließen 100Verzeichnis-Bäume durchlaufen

108Wechseln 95

vfprintf() 86, 1099Viren 1067vline() 701v-node-Tabelle 46vprintf() 86, 1099vsnprintf() 86vsprintf() 86, 1099

W

waitShell 1058

wait() 199, 222, 1126waitpid() 222, 225, 454, 1126wall 1216wc 1167wchar 1106WCONTIUED 225WCOREDUMP() 223wctob() 1089wctype 1106Webserver

Apache 584wenclose() 708Werkzeuge 859wgetch() 682, 707whatis 1220whereis 1167while-Schleife

Shell 1025who 1172whoami 1172WIFEXITED() 223WIFSIGNALED() 223WIFSTOPPED() 223wmouse_trafo() 713WNOHANG 225, 458WNOWAIT 225wprintw() 700Wrapper 54wrefresh() 702write 1216write() 52, 287, 422, 1114writev() 79WSTOPSIG() 223WTERMSIG() 223WUNTRACED 225wxFormBuilder 847wxWidgets 845

X

X Window 852X/OPEN 37Xenix 32Xlib 852XOPEN_VERSION 1113

Y

YACC 949

Z

zcat 1168Zeichen einlesen

Shell 1039Zeichenkette

Shell 984Zeichenketten vergleichen

Shell 1014Zeichenweise E/A 88Zeilenweise E/A 88Zeitmessung

GCOV 923GPROF 923Laufzeit einzelner Codzeilen 927Laufzeit von Funktionen 924Laufzeit von Prozessen 923Profiling 923TIME 923

zgrep 1168zip 1201zless 1168zmore 1168zsh 954Z-Shell 954Zugriffsdisziplinen 282Zugriffsrechte 1069Zugriffsrechte erfragen 116