watchdog



  • ich weiss schon dass er von flags spricht, aber die sehr wohl einen einfluss
    auf den share-mode. wenn die struktur overlapped ist kannst du keine ports mehr exklusiv holen.. stimmt doch oder?

    sorry, war vielleicht ein wenig kurz...



  • marc_ch schrieb:

    stimmt doch oder?

    Nein.



  • Threads hören sich kompliziert sind es aber nicht.

    Im Hauptprogramm schreibt man _beginthread(....),
    und anstelle von return schreibst du einfach _endthread();
    Das ist alles was du für deine Fall brauchst.

    #define ON 1
    #define OFF 0
    
    volatile int GlobalWatchDog=ON;
    volatile int GlobalEndThread=OFF;
    
     void TrivialWatchDog( PVOID VOID);
    
    int main()
    {
    .....
      // Sobald sie Watchdogüberwachung beginnen soll
      GlobalWatchDog++;
      _beginthread( TrivialWatchDog, 0, 0 );
    .....
      // in Regelmäßigen Abständen im Hautpprogramm dann ein (alle 600 mSec)
     GlobalWatchDog++;
    .......
      // Sobald die WatchdogÜberwachung enden soll
      GlobalEndThread=ON;
    ...
    return 0;
    }
    
    Die Threadfunktion sieht dann wie folgt aus.
    
    void TrivialWatchDog( PVOID VOID)
    {
    int i;
    if(OFF!=GlobalWatchDog)  // Programm lebt noch
     {
      GlobalWatchDog=OFF;
      for (i=0;i<20;i++)  
      {
       if (ON==GlobalEndThread)
       _endthread();
       Sleep(50);
      }
     }
     else  // Programm hat sich nicht gerührt
     {
     exit(-1);  // Als Beispiel ein harter Abbruch.
     }
        /* _endthread given to terminate */
    _endthread();
    }
    

    - Für die C++ Profis man kann das auch in eine eigene Klasse packen.
    - Ich weis, der direkte Zugriff auf Globale ist nicht im Sinne der reinen Leere
    - Ich weis, man sollte Globale Minimieren.
    - Ich weis, Accessfunktionen für die Variablen sind sicherer.
    - Die Timeoutzeit sollte man auch variable gestalten
    Aber dann wäre es dreimal so lang geworden und nicht so übersichtlich



  • Die globalen Variablen sollten als volatile gekennzeichnet werden. Außerdem würde ich auf _endthread verzichten und den Thread durch ein einfaches return beenden wollen.



  • Das mit dem volatile habe ich sinnvollerweise korrigiert.

    Aber warum _endthread durch return erstzen??

    ich fände es schon schön wenn die threadfunkrionen sich überhaupt nicht von
    einfachen C-Funktionen unterscheiden, aber in den Büchern wird immer auf
    _endthread hingewiesen



  • PAD schrieb:

    Aber warum _endthread durch return erstzen??

    Das _endthread würgt den Thread sofort und auf der Stelle ab. In Deinem Beispiel ist das auch kein Problem. Wenn nun aber Klassen dazukommen, werden keine Destruktoren aufgerufen. Und das finde ich bedenklich.

    Wenn Du den Thread einfach auslaufen lässt, funktioniert das wieder. Intern wird dann sowieso _endthread aufgerufen. Ein direkter Aufruf ist überflüssig.



  • Danke für die Information, ist Gott sei Dank in meinem Sinne.

    D.h. für die C-Fraktion ist es unerheblich ob sie return oder _endthread nimmt, für die C++ Fraktion ist es entscheidend das sie mit return arbeitet.

    Da _endthread nicht mehr Leistung als return bietet, sollte man return in beiden Fraktionen nutzen

    Sehe ich das richtig?



  • PAD schrieb:

    Sehe ich das richtig?

    Ja. Man kann sich aber auch in C ganz schnell 'ne Falle bauen:

    void DoSomething(void* pv)
    {
        _endthread();
    }
    
    void ThreadProc(void* pv)
    {
        void* pVoid = malloc(128);
        DoSomething(pVoid);
        free(pVoid);  // hier kommst Du nie an
    
      return;
    }
    

    Also immer schön auf _endthread verzichten. Dann kann auch nichts passieren. 😉



  • Schöne Sache, aber auch andere Statements als free werden genausoweinig ausgeführt.
    Ein thread ist kein Funktionsaufruf sondern der Start eines eigenen Fadens - er kehrt nicht an die Stelle des Aufrufs zurück - , der beim Beenden auch noch ein paar lustige Sync probleme machen kann.

    void DoSomething(void* pv) 
    { 
    Sleep(2000);
    
    pPad[0]=300;
        _endthread(); 
    } 
    
    int* pPad;
    
    int main() 
    { 
     if (0==(pPad = malloc(128)))
      {
       printf("\nmalloc failed\n);
       return -1
      }
    
      _beginthread(DoSomething(pVoid)); 
      Sleep(500);
      free(pPad);  // hier kommst du viel zu früh an
      return 0; 
    }
    

    ´tschuldigung natürlich muß DoSomething als thread aufgerufen werden.



  • Für mich sieht das gerade so aus, als ob du -King- nicht verstanden hast 😉
    DoSomething ist ja nicht die Thread-"Funktion", sondern eine Funktion, die aus den Thread (ThreadFunc) heraus aufgerufen wird.

    Du rufst ganz normal die Funktion DoSomething aus main auf und darin _endthread(); - was für einen Sinn soll das geben 😕



  • flenders schrieb:

    Du rufst ganz normal die Funktion DoSomething aus main auf und darin _endthread(); - was für einen Sinn soll das geben 😕

    Das hat natürlich keinen Sinn. Ich meine aber auch, daß das PAD bekannt ist. Man kann auch nicht einfach _beginthread auf einen Thread aufrufen, den man nicht gestartet hat.

    Er wollte halt auf allgemeine Synchronisations-Probleme hinweiseisen, die es selbstverständlich auch gibt. Im Grunde ist das ein Beispiel für meine Behauptung, daß auch _beginthread verboten gehört. Aber als ich das zum letzten Mal losgeworden bin, wurde mir ans Herz gelegt, mich erstmal mit den Basics zu beschäftigen. Deswegen werde ich jetzt auch nicht näher darauf eingehen.



  • Entschuldigung für den Schreibfehler im Code, ich habe ihn korrigiert.

    @ King Ohne die prügelen zu wollen, will soll man sonst in C multithreaded programmieren?
    Ich brauche dazu eine Funktion des Betriebssystems, welche mir einen Thread startet.



  • PAD schrieb:

    @ King Ohne die prügelen zu wollen, will soll man sonst in C multithreaded programmieren?

    Jedenfalls nie mit _beginthread. Das Problem ist, daß Dich diese Funktion über die Geschehnisse im Unklaren lässt. Der Rückgabewert ist zwar das Thread-Handle, aber leider ist es nicht gültig (wird intern geschlossen). Verwendest Du stattdessen _beginthreadex, bekommst Du ein gültiges Handle geliefert. Damit kannst Du auch Deine Synchronisations-Probleme auf einen Schlag lösen. Allerdings mußt Du nun das Handle selbst schliessen. Das ist aber nun wirklich kein Problem. Ach ja, die Thread-Funktion hat auch eine andere Signatur. Du kannst jetzt sogar einen Wert zurückgeben!

    UINT WINAPI DoSomething(void* pv)  
    {  
    Sleep(2000); 
    
    pPad[0]=300; 
    
    return(0);
    }  
    
    int* pPad; 
    
    int main()  
    {  
     HANDLE hThread;
     DWORD  dwCode;
    
     if (0==(pPad = malloc(128))) 
      { 
       printf("\nmalloc failed\n); 
       return -1 
      } 
    
      hThread = (HANDLE)_beginthreadex(DoSomething(pVoid));  
      WaitForSingleObject(hThread, INFINITE);
      free(pPad);  // hier kommst du an, wenn der Thread beendet ist
    
      if(WillHabenRückgabe)
          GetExitCodeThread(hThread, &dwCode);
    
      CloseHandle(hThread); // Thread-Handle zu Fuss schliessen
    
      return 0;  
    }
    

    Ich brauche dazu eine Funktion des Betriebssystems, welche mir einen Thread startet.

    Du sprichst von CreateThread? Das geht natürlich auch, nur mußt Du hier ganz genau wissen, was Du tust. Du übergehst damit die CRT. Solange Du im Thread nur API-Funktionen aufrufst, ist das auch kein Problem. Kommt eine Funktion aus der CRT ins Spiel, wird das schnell zum Abenteuer.

    Schau Dir die allseits beliebte Funktion strtok an. Diese speichert Ihren Zustand bis zum nächsten Aufruf (der z.B. mit NULL im ersten Parameter erfolgen kann). Stell Dir jetzt zwei Threads vor, die gleichzeitig strtok verwenden möchten.

    Probleme machen auch alle die Funktionen, die Fehler melden. Der VC löst das beispielsweise über errno. Aber welchen Fehler hält die Variable? Zu welcher Funktion aus welchem Thread gehört das?

    Wenn Du aber die CRT Funktion _beginthread/ ex verwendest, gibt es all diese Probleme nicht. Über die interne Initialisierung ist es möglich, daß jeder Thread seinen eigenen Zustand halten kann.



  • @-King- Danke für die Information über die Probleme von _beginthread.

    Mit dem Überlappen habe ich keine Probleme, ich wollte nur zu deinem Beispiel des nicht erreichbaren free´s noch ein anderes typisches Problem von multithreading zeigen.

    Die Lösung vor dem Verlassen des Hauptprogramms auf alle threads zu warten, kann auch nicht das Designproblem beheben das der thread einer inzwischen freigegebenen Variablen einen Wert zuweist.

    Eigentlich war deine Antwort mit _beginthreadex schon ausreichend, denn wenn du _beginthread ablehnst (mit sinnvollen Gründen) braucht man eine Alternative dazu, das diese schon durch _beginthreadex gegeben ist, war aus deinem Text nicht ersichtlich.



  • hab die folgenden header includiert

    #include <windows.h>
    #include <process.h>
    #include <iostream.h>

    und er mag das einfach ned machen:

    itsThreadHandle = (HANDLE) _beginthreadex(inputfunktion());

    und spuckt das aus:

    Borland C++ 5.6 für Win32 Copyright (c) 1993, 2002 Borland
    threads.cpp:
    Fehler E2268 threads.cpp 24: Aufruf der undefinierten Funktion '_beginthreadex'
    in Funktion MyThread::startThread()
    *** 1 Fehler bei der Compilierung ***

    was bringt das UINT WINAPI vor DoSomething(void* pv) eigentlich?
    was hat beginthreadex noch so für parameter (MSDN bringst mir nix)?

    Gruß TheChosn



  • TheChosn schrieb:

    Borland C++ 5.6 für Win32 Copyright (c) 1993, 2002 Borland
    threads.cpp:
    Fehler E2268 threads.cpp 24: Aufruf der undefinierten Funktion '_beginthreadex'
    in Funktion MyThread::startThread()
    *** 1 Fehler bei der Compilierung ***

    Ich könnte mir vorstellen, dass die Funktion im BCB anders heißt 🙄

    TheChosn schrieb:

    was bringt das UINT WINAPI vor DoSomething(void* pv) eigentlich?

    afaik ist UINT der Rückgabetyp und WINAPI (define aus windef.h) die Aufrufkonvention ( __cdecl )

    TheChosn schrieb:

    was hat beginthreadex noch so für parameter (MSDN bringst mir nix)?

    Wie hast du denn gesucht? http://msdn.microsoft.com/library/en-us/vccore98/html/_crt__beginthread.2c_._beginthreadex.asp



  • Hmm konnte nix finden was borland spezifisch wäre, das is in der header datei von borland.

    unsigned long _RTLENTRY _EXPFUNC _beginthreadex(void *__security_attr,
    unsigned __stksize,
    unsigned (__stdcall *__start)(void *),
    void *__arg,
    unsigned __create_flags,
    unsigned *__thread_id);

    Kannst du mir bitte noch kurz erklären was es mit den calling conventions auf sich hat?

    The routine at start_address must use the __cdecl calling convention and should have no return value.

    Wie finde ich die adresse einer Funktion raus, mag sie im konstruktor übergeben gehört ned der klasse.

    Gruß TheChosn



  • das mit den calling conventions bestimmt afaik, in welcher Reihenfolge die Parameter an die Funktion übergeben werden (von rechts nach links, oder umgekehrt) 🙄

    Du musst immho einfach den Namen übergeben (so wie z.B. bei Fensterklassen - WndProc)



  • Hast du dem Borland Compiler auch mitgeteilt, das du multithreaded arbeiten willst. Ich kann mich erinnern das wir eine ähnliche Fehlermeldung hatten als wir einmal unter MSVC 6.0 als wir in einer als singlethreraded definierten Applikation einen thread aufmachen wollten.



  • Wie kann ich meinem Borland Compiler denn das mitteilen?
    Bin leider ziemlicher Anfänger 😕

    Gruß TheChosn


Anmelden zum Antworten