HomeMagiCTest auf MagiCDie Zusatzprogramme für MagiC

11.18 Threads in MagiC

Das Konzept der Threads ermöglicht Quasi-Parallelität innerhalb einer Anwendung, und ist unter Betriebssystemen wie OS/2, MacOS oder UNIX schon länger bekannt. Im Gegensatz zum normalen Multitasking können dabei mehrere Threads zu einem Programm (bzw. Prozess) gehören. In MagiC werden Threads ab der Version 4.50 (01.04.96) unterstützt, und sind als Applikation implementiert, d.h. ein Thread besitzt unter MagiC eine eigene Applikations-ID. Das Konzept lehnt sich dabei an das von Sun Solaris 2.x an.

Dieser Abschnitt beschreibt die folgenden Punkte:

Querverweis: GEMDOS   Prozessfunktionen   Beispiel-Code

11.18.1 Threads und Signale

Beim Zusammenspiel von Threads und Signalen ist folgendes zu beachten: wird ein Prozess (z.B. per SIGSTOP) angehalten, so werden auch alle zugehörigen Threads angehalten; durch das SIGCONT-Signal können alle Threads wieder aufgeweckt werden. Falls ein Prozess per SIGTERM oder SIGKILL beendet wird, werden auch alle betroffenen Threads automatisch terminiert.

Die Signalbehandlung wird immer nur vom Haupt-Thread übernommen; dies ist derjenige, der mit Pexec gestartet worden ist. Während der Abarbeitung eines Signalhandlers wird deshalb auch nur der Haupt-Thread angehalten, und bei einem Aufruf von Psigreturn in diesen zurückgesprungen.

Achtung: Falls mehr als ein Thread die Signalmaske manipuliert, kann es zu Unstimmigkeiten kommen, falls die Maske nicht in der richtigen Reihenfolge wieder zurückgesetzt wird. Beispiel:

Thread-A rettet alte Maske
Thread-A ändert Maske
Thread-B rettet alte Maske
Thread-A restauriert alte Maske
Thread-B restauriert alte Maske

In diesem Fall wird die Signalmaske ungewollt verändert. Eine Lösung dieses Problems besteht darin, jedem Thread eine eigene Signalmaske zuzuteilen, und als effektive Signalmaske die Masken aller Threads durch eine Oder-Verknüpfung zu verbinden. Möglicherweise wird das in einer späteren Version von MagiC tatsächlich der Fall sein.

Querverweis: Threads in MagiC   Signale   shel_write   Prozessfunktionen

11.18.2 Threads und AES-Aufrufe

Bei der Entwicklung von eigenen Programmen muss unbedingt darauf geachtet werden, daß eine Multithread-sichere Bibliothek verwendet wird. Die Standardbibliotheken von Pure-C etwa sind in weiten Teilen diesbezüglich unbrauchbar. Es muss inbesondere darauf geachtet werden, daß jeder Thread sein eigenes global-Feld erhält. Betroffen sind daher die folgenden Funktionen:

Hinweis: Die original MagiC Dokumentation enthält Beispiele für Multithread fähige AES-Funktionen, an deren Aufbau man sich orientieren kann. Beachtet werden sollte noch, daß der Name eines Threads auf AES-Ebene ungültig ist, d.h. er kann nicht per appl_find oder appl_search gefunden werden.

Querverweis:
Threads und VDI-Aufrufe   Prozessfunktionen   AES-Bindings   Signale

11.18.3 Threads und VDI-Aufrufe

VDI-Aufrufe sind in den meisten Fällen nicht so kritisch wie AES-Aufrufe, da hier seltener ein Reentranz-Problem auftritt. Der Grund ist darin zu sehen, daß es bei Aufruf von VDI-Funktionen nicht so häufig zu Taskwechseln kommt, wie dies z.B. beim AES der Fall ist.

Problematisch sind VDI-Aufrufe jedoch immer dann, wenn auf Vektorfonts zugegriffen wird, da in diesen Fällen i.d.R. Plattenzugriffe notwendig sind, die in MagiC bekanntlich unterbrechbar sind. In einer solchen Situation kann es also zu einem Task-Switching kommen. Welche VDI-Befehle im einzelnen unterbrechbar sind kann an dieser Stelle nicht beantwortet werden; bei Bedarf ist dies mit den NVDI-Entwicklern abzuklären, so daß dann nur für diese Funktionen reentrante Bibliotheksfuktionen erforderlich wären.

Querverweis:
Threads und AES-Aufrufe   Prozessfunktionen   VDI-Bindings   Signale

11.18.4 Verteilung der Resourcen bei Threads

In MagiC laufen Threads auf demselben Prozess, besitzen jedoch eine eigene Applikations-ID, und sind somit eine selbstständige Task. Die folgende Tabelle gibt eine Übersicht über die Resourcen, die ein Thread selbst besitzt, bzw. vom Hauptprogramm benutzt.

Threads besitzen vom Hauptprogramm wird benutzt
• Userstack • Dateihandles
• Supervisor-Stack • Basepage
• Applikations-ID • Speicherblöcke
• Resource-Dateien • aktuelles Laufwerk/Verzeichnisse
• Menüzeile • Prozess-ID (PID)
• Desktop-Hintergrund • Domain (MiNT bzw. TOS)
• Fenster • umask
Message Queue • aktuelle DTA
• Mauszeiger Malloc-Flags
• VT52-Fenster (optional) • Kommandozeile und Environment
etv_term-Vektor • Signal-Handler und -maske
• Semaphoren • VT52-Fenster (optional)

Hinweis: Wie man sieht erhält ein Thread damit z.B. eine eigene AP_TERM Nachricht. Bei der Verwendung von Resource-Dateien ist darauf zu achten, daß ggfs. ein eigenes global-Feld benutzt wird.

Zu beachten ist ferner, daß Speicher, den der Thread alloziert, dem Prozess gehört, und bei Beendigung des Threads nicht automatisch freigegeben wird; gleiches gilt für geöffnete Dateien, die erst bei der Programmbeendigung geschlossen werden. Dies muss deshalb ggfs. vom Thread übernommen werden.

Achtung: Es ist unbedingt zu beachten, daß

Die Funktion Psemaphore ist bereits für Threads ausgelegt, und kann sowohl zur Synchronisation zwischen Prozessen als auch zwischen mehreren Threads eines Prozesses verwendet werden. Beim Beenden eines Threads werden alle von diesem blockierten Semaphoren automatisch freigegeben.

Nach Möglichkeit sollte z.Zt. nur der Haupt-Thread ein Pexec ausführen, nicht jedoch nebenläufige Threads. Theoretisch ist dies jedoch erlaubt, und zwar dann, wenn kein anderer Thread oder der Haupt-Thread Pexec aufgerufen hat, und der Haupt-Thread sich nicht beendet.

Das Problem liegt ganz einfach darin, daß z.Zt. Rücksprungadressen bei Pexec nicht im laufenden Prozess sondern im Parent abgelegt werden, und der Parent des vom Thread gestarteten Prozesses ungültig wird.

Falls ein Thread die Funktion Pterm ausführt, so wird z.Zt. nur dieser Thread beendet. Angemerkt werden soll auch noch, daß ein Thread andere Programme per shel_write (parallel) starten, und auf deren Beendigung warten kann.

Querverweis: Threads und AES-Aufrufe   Threads und VDI-Aufrufe   Prozessfunktionen   GEMDOS

11.18.5 Threads, Beispiel-Code zu

#include 
#include aes.h>

WORD global[15];
WORD ap_id;
WORD fmt_id;

LONG cdecl format_thread( struct fmt_parameter *par )
{
   WORD myglobal[15];
   WORD ap_id;

   /* wir braten das global-Feld der Haupt-APPL nicht über */

   ap_id = MT_appl_init(myglobal);
   (...)
}


/*********************************************************************
*
* Startet den Formatier-Thread.
*
*********************************************************************/

WORD start_format( VOID *param )
{
   THREADINFO thi;

   if§ (fmt_id < 0)   /* Thread noch nicht aktiv */
   {
      thi.proc = (VOID *) format_thread;
      thi.user_stack = NULL;
      thi.stacksize = 4096L;
      thi.mode = 0;
      thi.res1 = 0L;
      fmt_id = shel_write(SHW_THR_CREATE, 1, 0,
                          (BYTE *) &thi, param);
      return(fmt_id);
   }
   else
      return(-1);    /* Thread läuft noch */
}

WORD main( VOID )
{
   if ((ap_id = MT_appl_init(global)) < 0)
      Pterm(-1);
   else
   {
      (...)
      start_format( .... );

      while(...)
         (...);

      appl_exit();
      return(0);
   }
}

Querverweis: Threads   GEMDOS   Prozessfunktionen   Signale


HomeMagiCTest auf MagiCDie Zusatzprogramme für MagiC