Threading/Messages/Borland/Stil Fragen an die Pros



  • 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;
    }



  • Ich gebs auf...


Anmelden zum Antworten