Über Threads

ftComputing : Programme für die fischertechnik-Interfaces und -konstruktionskästen
  
ftComputing.de
Home
Back
Sitemap
Index
Links
Impressum
Mail
 

Allgemeines

umFish30.DLL ist durch Trennung von Zugriff auf das Interface und den Zugriff der Anwendung auf die Interface Werte threadfähig. Das geschieht durch Auslagerung des Interfacezugriffs in einen eigenen Poll-Thread des Steuerung über den MultiMediaTimer erfolgt. Im Poll-Thread werden die Daten des Interfaces in regelmäßigen Intervallen abgefragt und gleichzeitig die Aufträge der Anwendung übermittelt. Die Kommunikation mit der Anwendung erfolgt über einen Kontrollblock (den ftiDCB), der von der Anwendung asynchron ausgelesen bzw. besetzt wird.

So ist es möglich auf ein Interface ( ggf. mit angeschlossenem Slave (Extension Module) unabhängig aus verschiedenen Threads zuzugreifen. Der eigentliche Zugriff auf die nur einmal vorhandene Resource Interface erfolgt immer über den ebenfalls nur einmal vorhandenen Poll-Thread. Der Zugriff auf einzelne Ein- bzw. Ausgänge ist ohne weitere Maßnahmen möglich. Beim gleichzeitigen Zugriff auf alle M-Ausgänge ist eine Maskierung der vom eigenen Thread nicht genutzten M-Ausgänge im MotorStatus-Wort erforderlich, da umFish30.DLL keine Verwaltung von TeilResourcen bietet. Maskierung meint hier Erhalt des Status der "fremden" M-Ausgänge.

Die nachfolgenden Beispiele setzen die Klassen Thread und AutoResetEvent der .NET Framework Klassenbibliothek des Namespace System.Threading (using System.Threading;) ein. Übersichten und Details dazu siehe Hilfe System.Threading-Namespace und Thread-Member sowie WaitHandle-Member, AutoResetEvent-Member. Die .NET Framwork Klassen sind von Haus aus threadfest. Literatur Eric Gunnarson. Das Thread Kapitel ist instruktiv, es fehlt aber ein AutoResetEvent Beispiel.

Details

Thread Klasse zum Erstellen und Betreiben eines Threads :

private Thread robThread = new Thread(new ThreadStart robExecute));

Erstellen eines neuen Threads und der Nutzroutine als Callback Routine (Delegate). Die Nutzroutine ist also Bestandteil (eine Methode) der umgebenden Klasse. Der Thread wird erst durch robThread.Start() gestartet und durch Erreichen des Endes der Routine beendet.

AutoResetEvent Klasse zum Erstellen und Betreiben eines Synchronisations Mechanismus (Basis Waithandle), Alternative ManualResetEvent. AutoResetEvent wird nach Abfrage zurückgesetzt ManualResetEvent nicht :

private AutoResetEvent robReady = new AutoResetEvent(false);

Event ist nicht signaled (False) 

Programm RobStanze

Die Programme AmpelThread und RobStanze haben die gleiche Struktur. AmpelThread ist im Test wesentlich nervenschonender (es verhakt da nichts) und sollte der Ausgangspunkt eigener Bemühungen sein. RobStanze ist das attraktivere Modell, deswegen wird es hier besprochen. Bei den vorliegenden Programmen wird bei AmpelThread mit einem Intelligent Interface plus Extension Module an COM1 gearbeitet, bei RobStanze sind es Intelligent Interfaces an COM1 und COM2 (weil die Modelle so aufgebaut waren und weil die Verkabelung so einfacher ist (das Verbindungskabel des Extensionmodules ist zu kurz)) :

frmMain

Der Hauptthread mit Form und Gesamtsteuerung
ftR Instanz der Klasse FishFace zur Rob-Steuerung
ftS Instanz der Klasse FishFace zur Stanz-Steuerung
umFish30.DLL im Hintergrund : mit dem Poll-Thread
robReady Event : Roboter hat Teil plaziert
Standard Security, autoReset, not signaled
stanzeReady Event : Stanze kann neues Teil verarbeiten
Standard Security, autoReset, not signaled
robThread Thread mit der Robotersteuerung
stanzThread Thread mit dem Stanzprogramm

frmMain global

  • Anlegen der ftR und ftS Instanzen :
    private FishFace ftR = new FishFace(false, false, 0);
    private FishFace ftS = new FishFace(false, false, 0);
    ohne AnalogScan, ohne Slave, mit default PollIntervall
  • Thread Member
    private Thread robThread;
    private Thread stanzeThread;
    Instanziert werden kann hier noch nicht, da die Callback Routine nicht statisch ist.
  • Events
    private AutoResetEvent robReady;
    private AutoResetEvent stanzeReady;

cmdAction_Click

  • Herstellen der Verbindung zu den Interfaces :
    ftR.OpenInterface("COM2", false);
    ftS.OpenInterface("COM1", false);
    ohne Unterbrechung durch Application.DoEvents();
    in einer try - catch Klammer um Openfehler abzufangen. Weitere try/catch wären sinnvoll, aber man hört es auch so laut genug.
  • Anlegen der Threads und Events für Rob/Stanze
    robThread = new Thread(new ThreadStart(robExecute));
    stanzThread = new Thread(new ThreadStart(stanzThread));
    ohne sie zu starten
    robReady = new AutoResetEvent(false);
    stanzeReady = new AutoResetEvent(false);
    nicht signalisiert
  • Starten der Threads
    robThread.Start();
    stanzThread.Start();

robExecute   

Die Nutz-(CallBack/Delegate)Routine des Threads.

  • Anfahren der Home Position
    ftR.SetMotor(mSaule, ftiLinks, 15, 999);
    ftR.SetMotor(mArmV, ftiLinks, 15, 999);
    ftR.SetMotor(mArmH, ftiLinks, 15, 999);
    ftR.SetMotor(mGreifer, ftiLinks, 15, 999);
    ftR.WaitForMotors(0, mSaule, mArmV, mArmH, mGreifer);
    Alle vier Motoren des Robot werden simultan mit voller Geschwindigkeit gestartet (15), sie sollen 999 Impulse oder bis zum Erreichen des zugehörenden Endtasters laufen (ca. 360 Impulse sind eine volle Drehung, also bis zu den Endtastern). WaitForMotors wartet auf das Erreichen aller vier Endpositionen eine unbegrenzte Zeit (0).
  • BetriebsSchleife
    do {} while(!ftR.Finish());
    wird durchlaufen bis der Thread von außen einen EndeWunsch empfängt (siehe auch cmdEnde_Click).
  • In der Betriebsschleife
    frmThreadMain.lblStatus.Text = "....";
    Anzeige des aktuellen Status
    ftR.SetMotor(...
    ftR.SetMotor(...
    ft.WaitForMotors(0, ...);
    Ausführen der Teilschritte Greifen des Teils, Weg zur Ablage auf dem Transportband,
  • Weiter mit Warten auf stanzeReady
    stanzeReady.WaitOne();
    Ablegen auf dem Transportband nach dem Signal
    Nach dem Ablegen : Setzen Signal RobReady
    robReady.Set();
    und ohne Halt zurück zum Magazin.
  • Und nach Erhalt des Ende-Wunsches
    Fahren des Robots auf eine Ruheposition.

stanzExecute

Nutzroutine des Threads, ähnlich wie robThread.

  • Herstellen der Startposition
  • Betriebsschleife
  • In der Betriebsschleife
    Gleich zu Anfang Warten auf robReady und anschließendes Signalisieren stanzeReady
  • Weiter in der Betriebsschleife
  • Und nach Erhalt des Ende-Wunsches
    Abstellen der Lampen.

cmdEnde_Click

Kunstvolles Beenden des Stanzbetriebes :

  • Ende-Wunsch an Robot
    ftR.NotHalt = true;
    stanzeReady-Set();
    robThread.Join();
    NotHalt wird beim Schleifenende durch Finish ausgewertet, die Schleife und damit der Thread werden beendet. Vorher muß es aber erst soweit kommen : normales signalisieren StanzeReady. Anschließend Warten auf das Thread-Ende.
  • Ende-Wunsch an Stanze
    analog Robot
    daran denken es wird noch ein Teil benötigt, wenn die Testbefehle
    ftS.WaitForLow(ePhotoV);
    ftS.Pause(1234);
    noch vorhanden sind.
  • Abschlußarbeiten.