Vollständige Funktionsabarbeitung erzwingen



  • Hi Fans,

    ich habe mit VC++ 7 eine DLL geschmiedet, die per serieller Kommunikation Daten von einem Controller abholt. Die Host-Anwendung, die ich nicht Debuggen kann, ruft 3 Funktionen auf:

    1. Create(): Kommunikationsblock (Client-Objekt) erzeugen, Serielle Verbindung herstellen
    2. Communicate(): Daten über den Kommunikationsblock zyklisch schreiben/lesen
    3. Destroy(): Kommunikationsblock zerstören, Kommunikation beenden

    Starten und Daten holen funktioniert soweit, stoppen aber nicht:

    Communicate() wird in 99% der Fälle in der Hälfte beim Stoppen durch Destroy() unterbrochen. D.h. der Block mit den Schreib/Lesedaten wird zerstört und die Verbindung zum Controller gekappt. Danach wird versucht, die andere Hälfte von Communicate() auszuführen. Deht ja nicht, da Block schon weg -> Exception() -> Hostanwendung wird sofort terminiert. 😮

    Jetzt hab ich schon probiert mit CCriticalSection() den kritischen Abschnitt innerhalbt von Communicate() zu zementieren. Leider wird die Funktion immer noch unterbrochen.

    Ich bin mit meinem Latein am Ende.

    Tipps 😕

    MfG F98.



  • Du benötigst (vermutlich) eine CCriticalSection, auf die alle deine Funktionen zugreifen können. Und dann sollte auch die Destroy()-Funktion diese CritSec locken, bevor sie sich um die Aufräumarbeiten kümmert:

    CCriticalSection m_lock;
    
    void Communicate()
    {
      m_lock.Lock();
      ... // gesicherter Bereich
      m_lock.Unlock();
    }
    
    void Destroy()
    {
      m_lock.Lock();
      ... // Aufräumarbeiten
      m_lock.Unlock();
    }
    

    (Auf die Weise warten beide Funktionen, bis der jeweilige Partner fertig ist mit Arbeiten, bevor sie sich um ihren Kram kümmern können)



  • Ist es dabei egal, ob die CriticalSection innerhalb oder außerhalb der Klasse definiert wird?



  • Kommt darauf an, wie genau du die Arbeit synchronisieren willst:
    eine extern (oder static) definierte Critical Section gilt für alle Objekte deiner Klasse (d.h. nur eins gleichzeitig kann sich in Communicate() oder Destroy() aufhalten) - nützlich wenn alle deine Objekte mit den selben Ressourcen arbeiten wollen.
    eine Critical Section im Objekt gilt für jedes Objekt einzeln (Communicate()-Aufrufe von einem zweiten Objekt werden nicht beeinflußt) - das ist praktischer, wenn jedes Objekt seinen eigenen Speiicherbereich verwaltet und nur die Aufrufe intern synchronisieren will.



  • Vielen Dank für Deine Hilfe, hat mir weitergeholfen. 👍



  • Neue wundersame Dinge sind geschehen:

    Wie aus heiterem Himmel funktioniert das Locken nicht mehr korrekt. Ich habe die CCriticalSection genauso wie folgt verwendet:

    CCriticalSection m_lock;
    
    void Communicate()
    {
      m_lock.Lock();
    
      ... // gesicherter Bereich
    
      m_lock.Unlock();
    }
    
    void Destroy()
    {
      m_lock.Lock(); // Absturz
    
      ... // Aufräumarbeiten
    
      m_lock.Unlock();
    }
    

    Jetzt ist es aber so, dass wenn ich Destroy() aufrufe und m_lock.Lock(); aufgerufen wird es zum Absturz kommt. m_lock scheint also nicht mehr vorhanden zu sein, obwohl es statisch erzeugt wurde und die DLL noch nicht entladen worden ist.



  • *ping*



  • *pong* 😃

    "Absturz" ist ein ziemlich weitreichender Begriff - wie genau äußert sich "kommt es zum Absturz"? (ASSERT? Zugriffsverletzung? wasweiß ich?)

    Und du solltest das Programm mal durch den Debugger jagen, um einen genaueren Überblick über die Abläufe zu bekommen.



  • Wozu die Ciritical Section? Da wäre es doch sauberer ein Event Handle zu erzeugen und im Destroy-Fall darauf zu warten. (WaitForSingleObject). Damit hat man nämlich auch gleich einen maximalen Timeout den Communicate ihrem Treiben weiter fröhnen kann, bevor sie abgemurkst wird, und es besteht zu 100% (egal was Communicate jemals macht) kein Deadlock. Bei der Critical Section halte ich das durchaus für Kritisch....



  • Die Sache sieht so aus: Communicate() läuft vollständig durch und springt mit return raus. Danach erfolgt sofort der Aufruf von Destroy(), wo als erstes m_lock.Lock() drinsteht. Dort habe ich einem Breakpoint. Wenn ich mit F10 weiterspringe stürzt die Anwendung ab. Im Debugfenster wird ca. 6*10^23 mal

    Eine Ausnahme (erste Chance) bei 0x00234a86 in warwin.exe: 0xC0000005: Zugriffsverletzung-Leseposition 0x0000000c.
    

    ausgegeben, und zwar solange, bis

    Eine Ausnahme (erste Chance) bei 0x778acbb8 in warwin.exe: 0xC00000FD: Stack overflow.
    

    kommt. Und dann geht der Debugger in die Disassembly und das war's dann.



  • F98 schrieb:

    Die Sache sieht so aus: Communicate() läuft vollständig durch und springt mit return raus.

    Nach dem Unlock hoff ich doch?

    Was ist mit meinem obigen Vorschlag?



  • junix schrieb:

    F98 schrieb:

    Die Sache sieht so aus: Communicate() läuft vollständig durch und springt mit return raus.

    Nach dem Unlock hoff ich doch?

    Selbstverfreilich.

    Wie geht das mit dem Event Handle? Hab ich, glaube ich, noch nie programmiert sowas.

    😕



  • CreateEvent
    WaitForSingleObject
    SetEvent
    ResetEvent
    CloseEvent

    sind da wohl die passenden Funktionen die es sich mal zu gemüte zu führen lohnt (o:



  • Tue ich mir mal angucken. 🙂



  • Eine CriticalSection muss erst initialisiert werden, bevor sie benutzt werden kann. Falls du vielleicht gar nichts über CriticalSections weißt, solltest du dir genau zumindest die Hilfe dazu durchlesen. Verwende lieber EnterCriticalSection und LeaveCriticalSection sowie was du sonst an Funktionen dazu brauchen könntest. Lock und Unlock ist nicht so sauber wie es auf den ersten Blick aussieht.


Anmelden zum Antworten