Multithread-Programme entwickeln

Die Entwicklung von Multithread-Programmen ähnelt der Entwicklung von Programmen mit mehreren Prozessen. Die Entwicklung von Programmen besteht auch aus der Kompilierung und dem Debugging des Codes.

Multithread-Programm kompilieren

In diesem Abschnitt wird erläutert, wie ein Multithread-Programm generiert wird. Es beschreibt Folgendes:
  • Die erforderliche Headerdatei
  • Aufrufen des Compilers, der zum Generieren von Multithread-Programmen verwendet wird.

Headerdatei

Alle Subroutinenprototypen, Makros und andere Definitionen für die Verwendung der Threadbibliothek befinden sich in der Headerdatei pthread.h , die sich im Verzeichnis /usr/include befindet. Die Headerdatei pthread.h muss in jeder Quellendatei enthalten sein, die die Threadbibliothek verwendet.

Der Header pthread.h enthält den Header unistd.h , der die folgenden globalen Definitionen bereitstellt:

_POSIX_REENTRANT_FUNKTIONEN
Gibt an, dass alle Funktionen simultan verwendbar sein sollen. Verschiedene Headerdateien verwenden dieses Symbol, um ergänzende wiedereintrittsfähige Subroutinen zu definieren, wie beispielsweise die Subroutine localtime_r .
_POSIX_THREADS
Bezeichnet die POSIX -Thread-API. Dieses Symbol wird verwendet, um zu prüfen, ob die POSIX -Thread-API verfügbar ist. Makros oder Subroutinen können auf unterschiedliche Weise definiert werden, je nachdem, ob die POSIX oder eine andere Thread-API verwendet wird.

Die Datei pthread.h enthält auch errno.h, in der die globale Variable errno als threadspezifisch neu definiert wird. Die Kennung errno ist daher kein L-Wert mehr in einem Multithread-Programm.

Compiler aufrufen

Beim Kompilieren eines Multithread-Programms rufen Sie den C-Compiler mit einem der folgenden Befehle auf:
xlc_r
Ruft den Compiler mit der Standardsprachversion ansi auf.
Cc_r
Ruft den Compiler mit der Standardsprachversion extended auf.

Diese Befehle stellen sicher, dass die geeigneten Optionen und Bibliotheken verwendet werden, um der Single UNIX Specification, Version 2, zu entsprechen. Die POSIX -Threadspezifikation 1003.1c ist eine Untergruppe der Single UNIX Specification Version 2.

Die folgenden Bibliotheken werden automatisch mit Ihrem Programm verknüpft, wenn die Befehle xlc_r und cc_r verwendet werden:
libpthreads.a
Threadbibliothek
libc.a
Standard-C-Bibliothek
Der folgende Befehl kompiliert beispielsweise die Multithread-C-Quellendatei foo.c und erstellt die ausführbare Datei foo :
cc_r -o foo foo.c

Compiler für Entwurf 7 von POSIX aufrufen 1003.1c

AIX® bietet Quellcode-Kompatibilität für Draft 7-Anwendungen. Es wird empfohlen, dass Entwickler ihre Thread-Anwendung auf den neuesten Standard portieren.

Beim Kompilieren eines Multithread-Programms für die Draft 7-Unterstützung von Threads rufen Sie den C-Compiler mit einem der folgenden Befehle auf:
xlc_r7
Ruft den Compiler mit der Standardsprachversion ansi auf.
cc_r7
Ruft den Compiler mit der Standardsprachversion extended auf.
Die folgenden Bibliotheken werden automatisch mit Ihrem Programm verknüpft, wenn Sie die Befehle xlc_r7 und cc_r7 verwenden:
libpthreads_compat.a
Bibliothek 'Draft 7 Compatibility Threads'
libpthreads.a
Threadbibliothek
libc.a
Standard-C-Bibliothek

Um die Quellcodekompatibilität zu erreichen, verwenden Sie die Compilersteueranweisung _AIX_PTHREADS_D7. Außerdem müssen die Bibliotheken in der folgenden Reihenfolge verlinkt werden: libpthreads_compat.a, libpthreads.aund libc.a. Die meisten Benutzer müssen diese Informationen nicht kennen, da die Befehle die erforderlichen Optionen bereitstellen. Diese Optionen werden für Benutzer bereitgestellt, die nicht über den neuesten AIX -Compiler verfügen.

Anwendungen des Entwurfs 7 in &Symbol.unixspec; portieren

Es gibt Unterschiede zwischen Entwurf 7 und dem endgültigen Standard:
  • Geringfügige errno -Unterschiede. Am weitesten verbreitet ist die Verwendung von ESRCH , um anzugeben, dass der angegebene pthread nicht gefunden werden konnte. Entwurf 7 gibt häufig EINVAL für diesen Fehler zurück.
  • Der Standardstatus beim Erstellen eines pthread ist joinable. Dies ist eine signifikante Änderung, da sie zu einem Speicherleck führen kann, wenn sie ignoriert wird.
  • Der Standardzeitplanungsparameter pthread ist scope.
  • Die Subroutine pthread_yield wurde durch die Subroutine sched_yield ersetzt.
  • Die verschiedenen Planungsrichtlinien, die den Mutex-Sperren zugeordnet sind, unterscheiden sich geringfügig.

Speicherbedarf eines Multithread-Programms

AIX unterstützt bis zu 32768 Threads in einem einzelnen Prozess. Jeder einzelne pthread erfordert eine gewisse Menge an Prozessadressraum, sodass die tatsächliche maximale Anzahl von pthreads, die ein Prozess haben kann, vom Speichermodell und der Verwendung des Prozessadressraums für andere Zwecke abhängt. Die Speichermenge, die ein pthread benötigt, umfasst die Stackgröße und die Größe der Wächterregion sowie eine gewisse Menge für die interne Verwendung. Der Benutzer kann die Größe des Stacks mit der Subroutine pthread_attr_setstacksize und die Größe der Guardregion mit der Subroutine pthread_attr_setguardsize steuern.
Hinweis: Der veränderliche Grenzwert für die Stackgröße, der durch den Befehl ulimit -s festgelegt wird, gilt nur für den Stack des Hauptthreads der Anwendung.
In der folgenden Tabelle wird die maximale Anzahl von pthreads angegeben, die in einem 32-Bit-Prozess mit einem einfachen Programm erstellt werden können, das nichts anderes als create pthreads in einer Schleife mit dem Attribut NULL pthread tut. In einem realen Programm hängen die tatsächlichen Zahlen von der anderen Speicherbelegung im Programm ab. Bei einem 64-Bit-Prozess steuert die Subroutine ulimit , wie viele Threads erstellt werden können. Daher ist das Big-Data-Modell nicht erforderlich und kann tatsächlich die maximale Anzahl von Threads verringern.
Data Model -bmaxdaten Maximale Anzahl Pthreads
Kleine Daten n/a 1084
Big Data 0x10000000 2169
Big Data 0x20000000 4340
Big Data 0x30000000 6510
Big Data 0x40000000 8681
Big Data 0x50000000 10852
Big Data 0x60000000 13022
Big Data 0x70000000 15193
Big Data 0x80000000 17364
Die Umgebungsvariable NUM_SPAREVP kann festgelegt werden, um die Anzahl der virtuellen Ersatzprozessoren zu steuern, die von der Bibliothek verwaltet werden. Es ist nicht erforderlich, diese Variable zu ändern. In einigen Fällen können Anwendungen, die nur wenige Megabyte Speicher verwenden, den Speicheraufwand verringern, indem die Umgebungsvariable NUM_SPAREVP auf einen niedrigeren Wert gesetzt wird. Typische Einstellungen sind die Anzahl der CPUs auf dem System oder die maximale Anzahl der Prozessthreads. Das Festlegen dieser Variablen hat keinen Einfluss auf die Prozessleistung. Die Standardeinstellung ist 256.
Hinweis: Die Umgebungsvariable NUM_SPAREVP ist nur in AIX 5.1verfügbar.

Beispiel für ein Multithread-Programm

Das folgende kurze Multithread-Programm zeigt "Hello!" in Englisch und Französisch für fünf Sekunden. Kompilieren Sie mit cc_r oder xlc_r. F
#include <pthread.h>    /* include file for pthreads - the 1st */
#include <stdio.h>      /* include file for printf()           */
#include <unistd.h>     /* include file for sleep()            */

void *Thread(void *string)
{
        while (1)
                printf("%s\n", (char *)string);
        pthread_exit(NULL);
}

int main()
{
        char *e_str = "Hello!";
        char *f_str = "Bonjour !";

        pthread_t e_th;
        pthread_t f_th;

        int rc;

        rc = pthread_create(&e_th, NULL, Thread, (void *)e_str);
        if (rc)
                exit(-1);
        rc = pthread_create(&f_th, NULL, Thread, (void *)f_str);
        if (rc)
                exit(-1);
        sleep(5);

        /* usually the exit subroutine should not be used
           see below to get more information */
        exit(0);
}

Der Anfangsthread (der die Routine main ausführt) erstellt zwei Threads. Beide Threads haben dieselbe Eingangspunktroutine (die Routine Thread ), aber einen anderen Parameter. Der Parameter ist ein Zeiger auf die Zeichenfolge, die angezeigt wird.

Multithread-Programm debuggen

Die folgenden Tools sind für das Debugging von Multithread-Programmen verfügbar:
  • Anwendungsprogrammierer können den Befehl dbx für das Debugging verwenden. Zum Anzeigen threadbezogener Objekte sind verschiedene Unterbefehle verfügbar, einschließlich attribute, condition, mutexund thread.
  • Kernelprogrammierer können das Kernel-Debugprogramm verwenden, um das Debugging für Kernelerweiterungen und Einheitentreiber durchzuführen. Das Kernel-Debug-Programm bietet eingeschränkten Zugriff auf Benutzerthreads und verarbeitet in erster Linie Kernel-Threads. Mehrere Unterbefehle unterstützen mehrere Kernel-Threads und -Prozessoren, einschließlich:
    • Unterbefehl cpu , der den aktuellen Prozessor ändert
    • Den Unterbefehl ppd , der prozessorspezifische Datenstrukturen anzeigt
    • Unterbefehl thread , der Threadtabelleneinträge anzeigt
    • Unterbefehl uthread , der die uthread -Struktur eines Threads anzeigt
    Weitere Informationen zum Kernel-Debugprogramm finden Sie unter Kernel Extensions and Device Support Programming Concepts.

Kerndateianforderungen eines Multithread-Programms

Standardmäßig generieren Prozesse keine vollständige Kerndatei. Wenn eine Anwendung Daten in gemeinsam genutzten Speicherregionen, insbesondere Thread-Stacks, debuggen muss, muss ein vollständiger Kernspeicherauszug generiert werden. Führen Sie den folgenden Befehl als Rootbenutzer aus, um vollständige Kerndateiinformationen zu generieren:
	chdev -l sys0 -a fullcore=true

Jeder einzelne pthread wird zur Größe der generierten Kerndatei hinzugefügt. Die Größe des Kerndateibereichs, den ein pthread benötigt, umfasst die Stackgröße, die der Benutzer mit der Subroutine pthread_attr_setstacksize steuern kann. Für pthreads, die mit dem pthread-Attribut NULL erstellt wurden, addiert jeder pthread in einem 32-Bit-Prozess 128 KB zur Größe der Kerndatei und jeder pthread in einem 64-Bit-Prozess addiert 256 KB zur Größe der Kerndatei.