Multithreading mit der TAA

Einführung

Die TAA bietet verschiedene Möglichkeiten, bestimmte Aufgaben innerhalb eines (technischen ) Geschäftsvorfalls parallel zu verarbeiten. Dieses Dokument solle eine Übersicht der diese Möglichkeiten bieten, mit besonderer Berücksichtigung der Implementierung in .NET.

Steuerungen

Innerhalb einer Steuerung können durch die Verwendung des Gabelungskonstrukts Prozesse modelliert werden, die parallel ausgeführt werden sollen. Erst wenn alle Prozesse durchlaufen sind, wird die Verarbeitung der Steuerung beim Nachfolgekonstrukt, in diesem Fall das Entscheidungskonstrukt, fortgesetzt. Die einzelnen Prozesse arbeiten auf einer Kopie der TAA-Objektdaten, die erst bei Fertigstellung eines Prozesses wieder übernommen werden.

Ob die Prozesse zur Laufzeit auch parallel ausgeführt werden, kann über den Eintrag SpawnProcesses in der Config-Section der TAA-Registry gesteuert werden.

Grundsätzlich funktioniert die Parallelverarbeitung nur innerhalb eines Arbeitsgangs unter Verwendung der LAN-Infrastruktur. Auf der Geschäftsvorfall-Ebene wird noch keine Parallelverarbeitung unterstützt, 1) und werden solche Prozesse sequentiell abgearbeitet. Auch wenn die Steuerung als generiertes COBOL-Modul ausgeführt wird, werden die Prozesse sequentiell ausgeführt.

Asynchroner Aufruf

Auf Modulebene kann eine Parallelverarbeitung durch die Methode Spawn angestoßen werden. Im Gegensatz zu einem Call wird nicht auf die Fertigstellung des gerufenen Moduls gewartet, sondern wird der Aufruf asynchron durchgeführt. Das gerufene Modul bekommt eine Kopie der TAA-Objektdaten übergeben. Bei Fertigstellung des asynchron gerufenen Moduls bewahrt die Infrastruktur die Ergebnisse auf. Um die eventuell geänderten Daten zu übernehmen, muss durch einen Aufruf der Methode WaitFor auf die Fertigstellung gewartet werden.

Der Aufrufer kann auch verlassen werden, ohne auf die Fertigstellung zu warten. In dem Fall werden die Ergebnisse der asynchron gerufenen Module von der Infrastruktur verworfen.

Der asynchrone Aufruf kann in C/C++ und .NET 2) verwendet werden. In COBOL steht dies nicht zur Verfügung.

.NET

In .NET gibt es zusätzlich die Möglichkeit, bei einem asynchronen Aufruf eine Methode (Delegate) anzugeben, welche von der Infrastruktur bei der Fertigstellung ausgelöst wird. Diese Methode wird immer auf demselben Thread ausgelöst, in dem auch der Aufruf stattgefunden hat. Sie ist insbesondere für Interaktionen gedacht, um den UI-Thread während eines Aufrufs nicht zu blockieren.

Threads

Bei der Verwendung von Threads in der Implementierung eines Moduls ist zu berücksichtigen, dass die TAA nur einen Thread innerhalb der Implementierung kennt. Damit die TAA weitere Threads erkennen kann, sollte am Anfang die Methode ThreadAttach an TeamWiSE.TAA.Context 3) ausgelöst werden. Über die Methode <TeamWiSE.TAA.Context> ThreadDetach wird der Thread wieder abgemeldet. Bei Threads, die von der Infrastruktur angelegt werden (bspw. für SpawnModule) wird dies automatisch gemacht.

Außerdem müssen in der Implementierung eines Moduls selbst Sperrmechanismen programmiert werden, damit gleichzeitige Zugriffe auf TAA-Datenobjekte verhindert werden, wenn Änderungen stattfinden können, sei es durch andere Threads oder durch Modulaufrufe.

.NET

.NET stellt eine ganze Reihe von Möglichkeiten zur asynchronen Verarbeitung zur Verfügung, bei denen nicht direkt erkennbar ist, dass mehrere Threads verwendet werden. Es ist darum besondere Vorsicht vonnöten, wenn diese Möglichkeiten verwendet werden. Daher folgt jetzt eine Auflistung der .NET-Objekte, die innerhalb einer Modulimplementierung verwendet werden können, und was bei einer multithreaded-Implementierung zu berücksichtigen ist.

Außerdem werden zu der jeweiligen Klasse alle Methoden und Eigenschaften aufgelistet, mit der Angabe, ob diese threadsafe bzw. threadaffin sind. Eine Funktion kann sein:

  • threadsafe: kann von mehreren Threads gleichzeitig gerufen werden.
  • bedingt threadsafe: unterschiedliche Threads können gleichzeitig auf unterschiedliche Objekte zugreifen.
  • nicht threadsafe.

Ein Objekt bzw. eine Methode oder Eigenschaft ist threadaffin, wenn es/sie Verhalten enthält, durch das Funktionalitäten an einen spezifischen Thread gebunden sind; dies ist z.B. der Fall, wenn die Methoden des Objekts ausschließlich in dem Thread verwendet werden können, in dem dieses erzeugt wurde.

Es wäre vorstellbar, in Zukunft die Thread-Affinität einzelner Objekt und Methoden in den entsprechenden TAA-Klassen zu berücksichtigen, um bei Verletzung der Regeln eine entsprechende Ausnahmebehandlung 4) auszulösen.

In den nachfolgenden Aufstellung ist zu beachten, dass alle als „bedingt threadsafe“ markierten Eigenschaften und Methoden eigentlich als „nicht threadsafe“ zu betrachten sind. Eine darartige dreistufige Aufstellung ist auch eher unüblich. Die Angabe „bedingt Threadsafe“ steht an Stellen, wo wir vermuten, dass keine Daten für die Eigenschaft oder Methode benötigt werden, die parallel auf einem anderen Thread einen Einfluss auf die jeweilige Methode oder Eigenschaft haben könnten. So ist z.B. eine Änderung der Debug-, Enduser- oder TimestampOffset-Einstellungen eine denkbare (wenn auch unwahrscheinliche) Operation, bei der eigentlich alle „bedingt threadsafe“-Angaben sofort als „nicht threadsafe“ eingestuft werden müssten.

TaaEnv

Die Klasse TeamWiSE.TAA.taaEnv stellt eine Reihe von statischen Methoden und Eigenschaften zur Verfügung, damit eine Modulimplementierung sich bei der TAA anmelden kann (taaEnter, TaaRegister), bzw. auf Metadaten oder sonstige Informationen zugreifen kann.

Methode/Eigenschaft threadsafe threadaffin
cndClear() nein nein
cndHighestSeverity nein nein
cndRemove() nein nein
chdShowAll() nein nein
Conditions nein nein
EndUser ja nein
RegisterProcess() ja nein
ResourceNames() ja nein
Stage ja nein
taaEnter() ja ja
taaRegister() ja ja
taaReRegister() ja ja
UnregisterProcess() ja nein
Methoden, die Metadaten liefern ja nein

Context/ModlEnv

Der Einstieg in die TAA soll nur noch über die TeamWiSE.TAA.Context-Methoden taaEnter bzw. taaRegister erfolgen. Die bestehenden taaEnter/taaRegister-Methoden an der Klasse TeamWiSE.TAA.taaEnv sollen durch die Context-Methoden ersetzt werden.

Die Context-Instanz, die von diesen Methoden geliefert wird, kenne eine Eigenschaft ModlEnv, die der bisher bekannten ModlEnv-Instanz entspricht. Die Klasse ModlEnv ist nicht gegen eine threadübergreifende Nutzung abgesichert.

Nachfolgend sind die Methoden und Eigenschaften der Klasse ModlEnv beschrieben.

Methode/Eigenschaft threadsafe threadaffin
ActiveEvent ja nein
ApplicationSettings ja nein
Bc ja nein
Bp ja nein
CallModule() bedingt nein
cndAction bedingt nein
cndClassHdlClear() bedingt nein
cndClassHdlIdGet() bedingt nein
cndClassHdlIdSet() bedingt ja
cndClassHdlIsControl() bedingt nein
cndClassHdlIsId() bedingt nein
cndClassHdlIsProc() bedingt nein
cndClassHdlPop() bedingt ja
cndClassHdlProcGet() bedingt nein
cndClassHdlProcSet() bedingt ja
cndClassHdlPush() bedingt ja
cndClassHdlReplace() bedingt ja
cndClassHdlReset() bedingt ja
cndHdlClear() bedingt nein
cndHdlIdGet() bedingt nein
cndHdlIdSet() bedingt ja
cndHdlIsControl() bedingt nein
cndHdlIsId() bedingt nein
cndHdlIsProc() bedingt nein
cndHdlPop() bedingt ja
cndHdlProcGet() bedingt nein
cndHdlProcSet() bedingt ja
cndHdlPush() bedingt ja
cndHdlReplace() bedingt ja
cndHdlReset() bedingt ja
cndMarkedForRaise() bedingt nein
cndRaise() bedingt ja
cndRaised bedingt nein
cndRaiseMarked() bedingt ja
cndSet() ja nein
ctvEnv() bedingt ja
DataSet bedingt nein
InitStartRequest() ja nein
IsReentry ja nein
IsRegistered ja nein
Name ja nein
objDeclare() bedingt nein
SpawnModule() bedingt nein
State() ja nein
taaLeave() bedingt ja
TAAObjects bedingt nein
ToString() ja nein
Unregister() bedingt a
UseDateTimeForTimestamps bedingt nein
UseTimestamp bedingt nein
WaitFor() bedingt ja
WarnLevel bedingt nein
Yield() bedingt ja

TAAObject

Die Klasse TAAObject ist nicht gegen eine threadübergreifende Nutzung abgesichert. Die Instanz bleibt aber nach einem Modulaufruf oder auch einem Yield erhalten. Ein Modulaufruf auf einem anderen Thread kann den Inhalt jedoch ändern. Daher kann eine threadübergreifende Nutzung nur zum Teil über die C#-lock-Anweisung abgesichert werden. Denkbar wäre eine künftige Erweiterung, um den threadübergreifenden Zugriff mittels TAAObject-eigenen Lock/Unlock-Methoden abzusichern.

Unterschiedliche Instanzen können aber ohne Probleme auf unterschiedlichen Threads verwendet werden.

Methode/Eigenschaft threadsafe threadaffin
DataTable bedingt Nein
FillFromDataTable() bedingt Nein
Name Ja Nein
objAdd() bedingt Nein
objAddList() bedingt Nein
objCheck() bedingt Nein
objCheckField() bedingt Nein
objClassName bedingt Nein
objCompleteRef() Nein Nein
objCopy() bedingt Nein
objCount bedingt Nein
objCurrency bedingt Nein
objDclName Ja Nein
objDelete() bedingt Nein
objDestroy() Nein Nein
objDump() Bedingt Nein
objExist bedingt Nein
objFirst() Bedingt Nein
objGetField() bedingt nein
objInsert() bedingt nein
objInsertList() bedingt nein
objIsBOL bedingt nein
objIsCurrenncy() bedingt nein
objIsEmpty bedingt nein
objIsEOL bedingt nein
objIsValid ja nein
objLast() bedingt nein
objLength bedingt nein
objNew() bedingt nein
objNext() bedingt nein
objPosition bedingt nein
objPrev() bedingt nein
objPutField() bedingt nein
objReset() bedingt nein
objSkz nein nein
objSort() bedingt nein
objStructureName bedingt nein
objTypeName bedingt nein
objValidateField() bedingt nein
this[] (indexer) bedingt nein
TimestampFormat ja

BcObject/BpObject

Die Klassen BcObject und BpObject können grundsätzlich threadübergreifend verwendet werden. Sämtliche Methoden und Eigenschaften dieser Objekte sind jedoch von Fall zu Fall auf Threadsafety zu prüfen. So kann bspw. die Eigenschaft einer Workflowproperty zwar threadsafe abgefragt werden, es ist aber durch zusätzliche (anwendungsseitige) Mechanismen zu gewährleisten, dass Schlussfolgerungen aus der Abfrage eines Wertes gegen parallele Änderung der gleichen Workflowproperty abgesichert werden.

TAACondition

Die Klasse TAACondition ist von der .NET Klasse System.Exception abgeleitet, und ist nicht gegen einen threadübergreifenden Zugriff abgesichert. Conditions können nur auf dem Thread abgefangen werden, auf dem sie aufgeworfen werden. Der Zugriff auf eine Liste von Conditions (ModlEnv.cndRaised, taaEnv.Conditions) erstellt einen Snapshot der aktuellen Liste. Dieser Snapshot ist aber nur bedingt threadsafe, denn wenn eine Condition aus der Liste in einem anderen Thread gelöscht wird, wird dies nicht festgestellt, und kann u.U. zu einem Laufzeitfehler führen.

Methode/Eigenschaft threadsafe threadaffin
Associations nein nein
cndCode nein nein
cndGetArg() nein nein
cndGetAssoc() nein nein
cndGroup nein nein
cndHelpContextID nein nein
cndHelpFile nein nein
cndID nein nein
cndImpl nein nein
cndLine nein nein
cndLog() nein nein
cndMessage nein nein
cndModule nein nein
cndRaise() nein ja
cndRemove() nein ja
cndSetArg() nein nein
cndSetAssoc() nein nein
cndSeverity nein nein
cndShow() nein nein
cndTimestamp nein nein
cndTitle nein nein
Message nein nein
Severity() ja nein
ToString() nein

Services/Metadata

Die Klassen in den Namespaces TeamWiSE.Services bzw. TeamWiSE.TAA.MetaData können generell threadübergreifend verwendet werden. Daher wird hier auf eine Auflistung der einzelnen Methoden und Eigenschaften verzichtet.

CTV

Der Zugriff auf CTV ist nicht threadübergreifend abgesichert, und sollte auch nicht threadübergreifend verwendet werden. Daher wird hier auf eine Auflistung der einzelnen Methoden und Eigenschaften verzichtet.

1)
dies ist aber konzeptionell vorgesehen
2)
und unter Verwendung der COM-Schnittstelle/VB (obsolet)
3)
ab Rel. 8.15
4)
z.B. InvalidOperationException mit dem Text „Cross-Thread Operation not valid:“ und zusätzlichem Hinweis zum Kontext
faq:allg:taa_multithreading · Zuletzt geändert: 08.07.2016 08:14

Copyright © 1992-2024 TeamWiSE Gesellschaft für Softwaretechnik mbH         Adressen |  Kontakt |  AGB |  Datenschutzerklärung |  Impressum