Threading/Messages/Borland/Stil Fragen an die Pros



  • Servus,

    ok jetzt ist es soweit. Ich weiss nicht mehr wie ich weiter machen soll. Ich habe mich heute den ganzen Tag dämlich gegoogelt.

    Folgende Problemstellung:
    Ich soll in nächster Zeit die Steuerung einer Anlage neu schreiben. Hierzu habe ich eine "Trainbingsaufgabe". Diese besteht aus einer Aufzugsteuerung.
    Angedacht ist quasi ein Thread der sich mit dem Fahren befasst, einer der die Türen fährt und einer der die Anforderungen der Knöpfe behandelt. Diese drei sollen auch später miteinander kommunizieren.

    Als Start will ich nun erst einmal die Kommunikation der (vorläufigen) Oberfläche mit dem Thread der Anforderungen schreiben. Das möchte ich über eine Klasse die als Interface dienen soll realisieren. Die soll später dann zwischen Simulation und Hardware etc. umschalten können. Soll dann auch noch parametrierbar werden per config Files.

    Also momentan soll beispielsweise eine OnClick Funktion im Formular eine Nachricht absetzen, die diese Klasse bekommt und die dann entsprechend der Konfiguration die Nachricht an einen Empfänger weiterleiten (Also sagen wir jetzt einfach Anforderung Erdgeschoss). Diese weitergeleitete Nachricht soll der Anforderungs Thread bekommen und dann handeln.
    Ich könnte jetzt den Anforderungsthread ein Flag im Interface anpollen lassen über eine Schleife. Aber das soll ich nicht. Also soll der Thread eben pausieren bis ein Ereignis eintritt (Also die Nachricht von der Interface Klasse).

    Puh ich hoffe da kommt einer mit was ich will...

    Also mein Problem ist zum Einen das Realisieren der Threads und dann die Event basierte Kommunikation... Formular brüllt los, diese zwischenklasse reagiert und brüllt den Thread der Anforderung an, der auf eine Nachricht wartet. Der reagiert darauf und legt los, führt seine Aufgabe durch und wartet dann wieder auf ein Ereignis.

    Jetzt mein Problem... WIE? Mit WAS?

    Ich möchte den Borland Turbo C++ Explorer benutzen. Also MSVS fällt auf alle Fälle raus.

    Das Threading wollte ich über Boost machen... Nun habe ich ENDLICH Boost über den Umweg des 5.5 Compilers übersetzt bekommen. Habe die Thread Klasse durch ein Sample Programm integrieren wollen (Aus der EN Wiki unter Boost.) und bekomme in der function_template.hpp lauter Fehler.

    [C++ Fehler] function_template.hpp(613): E2188 Ausdruckssyntax
    [C++ Fehler] function_template.hpp(683): E2299 Template-Spezialisierung kann aus 'function<Signature,Allocator>' nicht generiert werden
    [C++ Fehler] function_template.hpp(688): E2270 > erwartet
    [C++ Fehler] function_template.hpp(688): E2040 Deklaration nicht ordnungsgemäß abgeschlossen
    [C++ Fehler] function_template.hpp(688): E2190 Unerwartetes }
    [C++ Fehler] function_template.hpp(613): E2108 Ungültige Verwendung von typedef 'T0'
    [C++ Fehler] function_template.hpp(613): E2108 Ungültige Verwendung von typedef 'T0'
    [C++ Fehler] function_template.hpp(613): E2293 ) erwartet
    [C++ Fehler] function_template.hpp(683): E2299 Template-Spezialisierung kann aus 'function<Signature,Allocator>' nicht generiert werden
    [C++ Fehler] function_template.hpp(688): E2270 > erwartet
    [C++ Fehler] function_template.hpp(688): E2040 Deklaration nicht ordnungsgemäß abgeschlossen
    [C++ Fehler] function_template.hpp(688): E2190 Unerwartetes }
    [C++ Fehler] function_template.hpp(613): E2108 Ungültige Verwendung von typedef 'T0'
    [C++ Fehler] function_template.hpp(613): E2293 ) erwartet
    [C++ Fehler] function_template.hpp(683): E2299 Template-Spezialisierung kann aus 'function<Signature,Allocator>' nicht generiert werden
    [C++ Fehler] function_template.hpp(688): E2270 > erwartet
    [C++ Fehler] function_template.hpp(688): E2040 Deklaration nicht ordnungsgemäß abgeschlossen
    [C++ Fehler] function_template.hpp(688): E2190 Unerwartetes }
    [C++ Fehler] function_template.hpp(613): E2108 Ungültige Verwendung von typedef 'T0'
    [C++ Fehler] function_template.hpp(613): E2293 ) erwartet
    [C++ Fehler] function_template.hpp(683): E2299 Template-Spezialisierung kann aus 'function<Signature,Allocator>' nicht generiert werden
    [C++ Fehler] function_template.hpp(688): E2270 > erwartet
    [C++ Fehler] function_template.hpp(688): E2040 Deklaration nicht ordnungsgemäß abgeschlossen
    [C++ Fehler] function_template.hpp(688): E2190 Unerwartetes }
    [C++ Fehler] function_template.hpp(613): E2108 Ungültige Verwendung von typedef 'T0'
    [C++ Fehler] function_template.hpp(613): E2228 Zu viele Fehlermeldungen oder Warnungen

    Also habe ich eine Alternative gesucht... Finde aber nicht so recht etwas.

    Momentan habe ich eher ein riesiges Fragezeichen über meinem Kopf. Ich muss zum Einen Threads programmieren und zum Anderen dafür sorgen, daß die untereinander quasseln und auf Nachrichten reagieren.

    Mir würde im Grunde schon ein Tip weiterhelfen wie ich Thread A eine Nachricht schicken lassen kann auf die Thread B reagiert.

    Ich weiß es klingt durcheinander. Aber so fühle ich mich auch gerade. 🙄



  • Ja Multi-Threading ist so ne sache:) du kannst Thread komunizieren lassen... google mal nach Thread Syncronistion (Semaphoren etc.) Du kannst über Event Thread starten und stoppen:)

    Bsp. Kannst du Thread A in ein Warte Zustand schicken (WaitForSingleObjekt), bis Thread B ein event an Thread A schickt etc.

    Oder Thread Knöpfe, welcher städnig in 100ms Intervalen die Könöfpe abfrägt. wenn ein Knopf getrück wurde Kannst du dem Tür auf/zu trhead mitteilen jetzt türe schliessen. und so lange keine Tasteneingaben aufnehmen etc.

    Du musst dir vll. noche gedanken machen, das der Tasten/Knopf Eingabe- Thread die eingaben in eine Liste Speichert, das der Lift ja dann diese Abahr- List abarbeiten muss.



  • Ich bin jetzt soweit, daß ich aus den Libs des BDS die Klassen TEvent und TThread im Auge habe.

    Bisher spiele ich damit rum.

    Mein Problem liegt im Moment darin, daß ich nicht weiß wie der Konstruktor der TEvent genau funktioniert. Es gibt wohl zwei Versionen. Einer hat als Parameter UseCOMWait und der Andere hat 4 oder 5 Parameter. Dummerweise weiss ich nur bei zweien was der Konstruktor von mir will.

    Das Pollen ist übrigends genau DAS was ich nicht soll.



  • Pollen?

    Sorry kenn mich nur bischen mit MFX und c++ (aPI) aus was Thread angeht..

    Hast mal nach Thread Syncronistion gegoogelt??



  • Ich habe zwei Tage google und die Board Suche gequält. Das war mein Wochenende.

    Momentan mach ich das über TEvents, die einfach global angelegt sind. Die Threads lauschen dann mittels WaitFor auf das Event. Ob das wirklich die astreine Methode ist kann ich nicht sagen.

    Das mit dem Thread Knöpfe was du da meinst ist Pollen. Zyklisch abfragen. Aber so ein Vorgang braucht Rechenzeit. Die habe ich nicht. Ich muss 400MB große Bilder verarbeiten. (Spektralbilder) Also muss ich Event gesteuert arbeiten und die Threads schlafen lassen.

    Praktisches Beispiel, das mir gerade als Übung dient:

    Thread A ist beispielsweise ein Formular. (Später dann eine IO Steuerung über CanBus oder so). Thread B ist ein Thread der die Anforderungen eines Fahrstuhls bearbeitet. (angefordert <-> nicht angefordert). Thread B soll nun auf einen Knopfdruck reagieren und ansonsten schlafen. Thread A hat einen Knopfdruck bekommen (wie auch immer...). A muss nun B anbrüllen "Ey mach mal was, da hat einer gedrückt". B soll jetzt also auf das Event BUTTON_PRESSED reagieren.

    Momentane Lösung:

    TEvent BUTTON_PRESSED ist global definiert.

    B steht mit BUTTON_PRESSED.WaitFor(INFINITE) auf Warteposition.

    Ein Knopf wird gedrückt und A macht BUTTON_PRESSED.set(). Daraufhin reagiert die WaitFor Prozedur und lässt B weiterlaufen, der dann seine Routine abhandelt, bis er wieder an der Stelle waitfor landet.

    Code kommt auch irgendwann anch 😃

    Meine Frage an die Berufsentwickler hier: Ist das so halbwegs gut oder ist das ein Verbrechen an C++ was ich da treibe? Das Ganze ist kein *schnips* Projekt zuhause, sondern eine Anlagensteuerung und meine Diplomarbeit. Ich bin allerdings kein Informatiker sondern Optotechniker und Bildverarbeiter.



  • was benutzt du für ein framework? für die einzelnen Fenster welceh buttons enthalten, exitstire ja ne message loop, welche die Eregnisse des Fenster (Knopfdruck) abfängt...



  • BDS VCL.

    Jaaa klar existiert ein MEssagehandler für OnClick. ABER das Ganze soll ja mit Hardware später laufen. Das Formular ist ja nur zum Simulieren.



  • ja gut ... da hast ja divere Interrups.. welche jeweis ein Thread darstellen ... und einer der Interrups fängt bspw. input message ab...

    somit werden dann die thread nacheinader abgearbeitet , wo bei die anderen im aktuelle zustanden angehalten werden... wenn einer läuft

    und das ganze willst du simuliaren nehm ich an.. d.h. du musst thread coden die immer serial abgerabitet werden. seh ic hdas richtig?

    und was für hardware ist das? hast du da keine emulator mit ein uns ausgeägen etc.?



  • Momentan geht es darum den Zustandsautomaten zu konstruieren. Hardware ist NOCH nicht im Spiel. Ich baue quasi erstmal die SoftSPS zusammen. Deswegen soll ja eine Schnittstellenklasse rein. Damit ich dann die IO (Jetzt ein TForm, später IO Software zur Hardware) wechseln kann.

    Ich habe mir gerade einen Thread gebastelt der auf ein Set wartet und reagiert. Ich komme also vorwärts.

    Weiss nicht ob wir aneinander vorbeireden.

    Hmmm ich würd schon sagen, daß ein Thread quasi die Interruptverteilung bildet und die Anderen dann darauf reagieren.

    2m hinter mir läuft gerade eine Konferenz. Das Konzentrieren ist ein wenig schwierig *g*



  • ja gut ... thread laufen ja real nicht paralell ab sonder nacheinander.. hast schon recht..

    Aber was hat das ganze mit SPS zu tun?? Ne eigene SoftSPS programmeren??

    Und ein windoes rechner is tnich echtzeitfähig wie SPS bedenke das:)

    Ich abrbeite im augenblick an einem ähnlichen projekt:) hehe .. eine Anlagen Simulation;) wa sspäter evtl. in ner SPS integirest wird:)



  • Shogun schrieb:

    Momentan habe ich eher ein riesiges Fragezeichen über meinem Kopf. Ich muss zum Einen Threads programmieren und zum Anderen dafür sorgen, daß die untereinander quasseln und auf Nachrichten reagieren.

    du könntest z.b. die in windows schon eingebauten message queues dafür benutzen. beispiel:

    #include "stdio.h"
    #include "windows.h"
    
    DWORD __stdcall Thread (void *p)
    {
       while (1)
       {
          MSG msg;
          GetMessage (&msg, NULL, 0, -1);
          printf ("Thread:%d msg: %d (%d/%d)\n", GetCurrentThreadId(), msg.message, msg.wParam, msg.lParam);
       }
    
       return 0;
    }
    
    int main ()
    {
       DWORD tid1, tid2;
       CreateThread (NULL, 0, Thread, 0, 0, &tid1);  // zwei threads starten
       CreateThread (NULL, 0, Thread, 0, 0, &tid2);  
       Sleep (1000);
       PostThreadMessage (tid1, WM_USER+1,2,3);      // an beide 2 messages schicken
       PostThreadMessage (tid2, WM_USER+2,4,5);
       PostThreadMessage (tid1, WM_USER+3,6,7);
       PostThreadMessage (tid2, WM_USER+4,8,9);
    }
    

    die threads warten mit 'GetMessage', bis etwas in der queue ist.
    wenn sie nicht warten sollen, dann 'PeekMessage' mit PM_REMOVE benutzen.
    🙂



  • Also das mit den Thread-Messages ist eine leidige Sache, wie ich festgestellt habe. Die können tatsächlich verloren gehen, wenn die Nachrichtenwarteschlange nicht schnell genug abgearbeitet wird.

    WaitForSingle- / WaitForMultipleObjects sind wohl die sicherste Alternative. Allerdings habe ich dafür nicht TEvent genutzt, sondern die Alternativen aus der WinAPI (Also über HANDLE, zB HANDLE hEventBlaBlaBla = CreateEvent(/*Parameter*/);)
    Auch die Beendigung der Threads habe ich ein Event realisiert, da die TThread::Terminate()-Funktion so ihre Macken hat. Merkt man, sobald man das Programm beenden und die Threads geregelt beenden möchte. Extreme hohe CPU-Last, Destruktor wird meist nicht mehr aufgerufen...

    Schau Dir mal diesen Thread an:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-167833-and-highlight-is-.html
    Insbesonder die Links von junix in der ersten Anwort sind sehr hilfreich.



  • Joe du hast mich jetzt doch ins Wanken gebracht mit deinem Thread. Ich werde mir jetzt das Multithreading Kapitel aus dem Petzold verpassen. Dann werde ich zweimal das gleiche Programm schreiben. Einmal mit der VCL und einmal auf der API selbst. Ich habe hier aus einer Laborübung noch eine kleine Stoppuhrklasse, die auf dem Windows internen Timer basiert.
    Dann schaue ich mir mal an was schneller ist. Natürlich kann es passieren, daß ich ncah dem Einlesen gleich sage, daß die API besser ist, wenn man sie kennt.

    Ich habe momentan noch ein Wenig Bammel vor der API. Aber im Petzold scheint es ganz gut erklärt zu sein. Naja sind ja nur 20 Seiten. Attackeeee!



  • Ja, Sorry. 😉 Ich mach normalerweise auch einen Riesenbogen um die WinAPI. Die ist mir im Regelfall viel zu umständlich...

    Die verwendeten Threads sind tatsächlich auch VCL-Threads. Nur bei den Events / Semaphores und den CriticalSections habe ich die WinAPI-Funktionen verwendet. Erstere weil ich die Handles für die WaitFor...-Funktionen sowieso brauchte und mir die Anwendung mit den WinAPI-Funktionen einleuchtender war, zweitere, weil es dort ein TryLock() gibt, welches ich bei dem VCL-Pendant vermisst habe.



  • Wo ist der unterschied zwischen Try Lock und Aquire? Wartet das Programm (sorry der Thread) bei Try Lock nicht bis die Variable wieder frei ist?



  • Joe_M. schrieb:

    Also das mit den Thread-Messages ist eine leidige Sache, wie ich festgestellt habe. Die können tatsächlich verloren gehen, wenn die Nachrichtenwarteschlange nicht schnell genug abgearbeitet wird.

    klar, die kann voll werden, aber man kann was dagegen tun:

    msvc help file schrieb:

    Call PostThreadMessage. If it fails, call theSleep function and call PostThreadMessage again. Repeat until PostThreadMessage succeeds.



  • @Shogun: Bei TryLock() kann man prüfen, ob man die CriticalSection sperren kann, wenn ja, wird gesperrt, ansonsten kann man den Thread noch was anderes tun lassen, zB ein anderes Objekt bearbeiten, oder die Nachrichtenwarteschlange prüfen.
    Bei der VCL-CriticalSection muss gewartet werden, bis er Zugriff auf das Objekt hat.

    @Vista: Das Problem ist nicht das Absetzen der Nachricht, sondern das Empfangen der Nachricht. Das Absetzen kann problemlos funktionieren, aber wenn der Empfängerthread gerade in einer Funktion steckt und die Warteschlange einige Sekunden nicht prüft, verwirft Windows die Nachricht.
    Ich hab das anfangs auch für eine einfache und ausreichende Lösung gehalten. Erst als die Threads komplexer wurden und recht viel CPU-Last erzeugt haben, ist mir aufgefallen, dass regelmäßig Nachrichten verloren gehen. Natürlich kann man den Empfängerthread antworten lassen und sollte die Antwort ausbleiben den Sendethread die Nachricht erneut senden lassen, aber das ist viel zu viel Aufwand. Events sind da einfacher.



  • Interessant... Die API bietet mir nicht nur Events sondern gleich richtige Message Qeues. Würde mein Thread terminieren vereinfachen... Statt immer wieder Terminated abfragen zu müssen und ein TimeOut bei den WaitFor zu benutzen, damit der nicht hängenbleibt, kann ich einfach GetMessage benutzen. Einfach eine Exit Message erzeugen. Hat was... Oder seh ich da was grundsätzlich falsch?

    HOPPLA... Sorry vista du hast das ja bereits empfohlen. Ich hab hier jetzt parallel im Petzold und auf codeproject.com drüber gelesen.

    Event gibts nur an und aus im Endeffekt... Ich habe mir schon eine eigene Event Klasse bauen müssen, weil ich auf AN und AUS reagieren will... Das kann ich mir mit den Messages sparen... case MESSAGE_ON --> blabla, case MESSAGE_OFF--> blabla und zu guter Letzt case MESSAGE_KILL --> die motherfucker.

    Ich seh den Vorteil jetzt darin, daß ich das Warten auf ein Event nicht immer wieder mittels Timeout unterbrechen muss um nachzufragen ob der Thread zuende sein soll. Sollte eigentlich einen Hauch Rechenzeit sparen *grübel*

    Mal ganz davon abgesehen, daß die Bezeichner von einer MEssage die geschickt wird einfacher zu lesen ist im Code als eine Reaktion auf ein Event. Und ich spar mir das Reset (Jaaaa WaitForObject macht automatisch Reset). Nachricht ist einfach Fire and Forget.

    Oh Gott! Ich hab Fieber! Ich fange an die API zu mögen!



  • Tja, ich weiß nicht, was ich noch sagen soll... Lies Dir vielleicht nochmal den Thread durch, den ich verlinkt habe.
    Auf jeden Fall würde ich (aus meiner persönlichen Erfahrung heraus) sagen, dass es mit den Messages früher oder später Probleme geben wird. Ich habe erst durch die Verwendung von Events und Semaphores eine stabiles und zuverlässiges System erhalten.



  • Noch bin ich am Profiling und rumprobieren.

    Call PostThreadMessage. If it fails, call theSleep function and call PostThreadMessage again. Repeat until PostThreadMessage succeeds.

    Wie vista zitiert hat. Der postende Thread will ja was und hat zu warten falls es nicht klappt.

    Naja mal schauen. Ich hab was mit Events laufen und ich hab was mit Messages laufen. Unter Umständen mixe ich fröhlich VCL und API.

    Was mir bisher verloren ging war die allererste Nachricht. Da war wohl die Queue noch nicht existent.
    Vorteil sehe ich auch darin, daß das eine Warteschlange ist, die abgearbeitet wird... Also von 5000 generierten Messages hatter keine verloren in meinem Beispielprogramm.

    EDIT: Aber bei mehr als 5000 verlierter wohl welche 😃

    Nichts ist unmöööglich TOYOOOODAAAA

    Windows 2000/XP: There is a limit of 10,000 posted messages per message queue. This limit should be sufficiently large. If your application exceeds the limit, it should be redesigned to avoid consuming so many system resources. To adjust this limit, modify the following registry key:

    HKEY_LOCAL_MACHINE
    SOFTWARE
    Microsoft
    Windows NT
    CurrentVersion
    Windows
    USERPostMessageLimit
    The minimum acceptable value is 4000.

    unsigned int n=0;
    while (Rechtschreibung == false) {
    Zuletzt bearbeitet von Shogun am 15:35:35 17.04.2007, insgesamt n-mal bearbeitet
    ++n;
    }


Log in to reply