EnterCriticalSection Deadlock

Nachdem, was zu sein scheint ein dead-lock-situation bei multi-threaded-logging-Anwendung.

Wenig hintergrund:

Meine Hauptanwendung 4-6 threads laufen. Der Haupt-thread verantwortlich für die überwachung der Gesundheit der verschiedenen Dinge, die ich Tue, Aktualisierung GUIs, etc... Dann habe ich ein sende-thread und einen Empfangs-thread. Die sende-und Empfangs-threads zu sprechen zu physischen hardware. Brauche ich manchmal, um die debug-Daten, dass die sende-und Empfangs-threads zu sehen sind; D. H. das drucken auf einer Konsole, ohne diese zu unterbrechen aufgrund Ihrer zeitkritischen Natur der Daten. Die Daten, die durch die Art und Weise, auf einer USB-bus.

Aufgrund des threading-Art der Anwendung, erstellen Sie eine debug-Konsole, dass ich Nachrichten senden kann, um aus meinen anderen threads. Die debug-beim bedienungsterminal läuft als niedrig priorisierter thread und implementiert einen Ringpuffer, so dass, wenn Sie drucken, um die debug-Konsole, die Nachricht ist schnell gespeichert, um einen ring-Puffer und sets und event. Die debug-Konsole-thread sitzt WaitingOnSingleObject Ereignisse aus der gebundenen Botschaften, die kommen. Wenn ein Ereignis erkannt wird -, Konsolen-thread-updates ein GUI-display mit der Meldung. Einfach, eh? Die Druckerei anrufen und die Konsole thread einen kritischen Abschnitt verwenden, um den Zugriff Steuern.

HINWEIS: ich einstellen kann das ring-Puffer-Größe, wenn ich sehe, dass ich mich fallenlassen Nachrichten (zumindest ist das die Idee).

In einem test-Anwendung, die Konsole funktioniert sehr gut, wenn ich rufen Sie die Print-Methode langsam über Maus-Klicks. Ich habe einen button, den ich drücken kann, zum senden von Nachrichten an die Konsole und es funktioniert. Allerdings, wenn ich jede Art von Last (viele Aufrufe von Print-Methode), alles dead-locks. Wenn ich trace die dead-lock, meine IDE-debugger Spuren zu EnterCriticalSection und sitzt dort.

HINWEIS: Wenn ich entfernen Sie die Sperren/Entsperren der Anrufe und benutzen Sie einfach die EINGABETASTE/LeaveCriticalSection (siehe code) arbeite ich manchmal, aber noch immer finde mich in einem dead-lock-situation. Um auszuschließen, deadlocks auf stack push/pops, ich nenne Sie Enter/LeaveCriticalSection direkt jetzt, aber diese nicht lösen, mein Problem.... Was ist denn hier Los?

Hier ist eine Print-Anweisung, die es erlaubt mir zu übergeben, die in eine einfache int, um die display-Konsole.

void TGDB::Print(int I)
{
    //Lock();
    EnterCriticalSection(&CS);

    if( !SuppressOutput )
    {
        //swprintf( MsgRec->Msg, L"%d", I);
        sprintf( MsgRec->Msg, "%d", I);
        MBuffer->PutMsg(MsgRec, 1);
    }

    SetEvent( m_hEvent );
    LeaveCriticalSection(&CS);
    //UnLock();
}

//My Lock/UnLock methods
void TGDB::Lock(void)
{
    EnterCriticalSection(&CS);
}

bool TGDB::TryLock(void)
{
    return( TryEnterCriticalSection(&CS) );
}

void TGDB::UnLock(void)
{
        LeaveCriticalSection(&CS);
}

//This is how I implemented Console's thread routines

DWORD WINAPI TGDB::ConsoleThread(PVOID pA)
{
DWORD rVal;

         TGDB *g = (TGDB *)pA;
        return( g->ProcessMessages() );
}

DWORD TGDB::ProcessMessages()
{
DWORD rVal;
bool brVal;
int MsgCnt;

    do
    {
        rVal = WaitForMultipleObjects(1, &m_hEvent, true, iWaitTime);

        switch(rVal)
        {
            case WAIT_OBJECT_0:

                EnterCriticalSection(&CS);
                //Lock();

                if( KeepRunning )
                {
                    Info->Caption = "Rx";
                    Info->Refresh();
                    MsgCnt = MBuffer->GetMsgCount();

                    for(int i=0; i<MsgCnt; i++)
                    {
                        MBuffer->GetMsg( MsgRec, 1);
                        Log->Lines->Add(MsgRec->Msg);
                    }
                }

                brVal = KeepRunning;
                ResetEvent( m_hEvent );
                LeaveCriticalSection(&CS);
                //UnLock();

            break;

            case WAIT_TIMEOUT:
                EnterCriticalSection(&CS);
                //Lock();
                Info->Caption = "Idle";
                Info->Refresh();
                brVal = KeepRunning;
                ResetEvent( m_hEvent );
                LeaveCriticalSection(&CS);
                //UnLock();
            break;

            case WAIT_FAILED:
                EnterCriticalSection(&CS);
                //Lock();
                brVal = false;
                Info->Caption = "ERROR";
                Info->Refresh();
                aLine.sprintf("Console error: [%d]", GetLastError() );
                Log->Lines->Add(aLine);
                aLine = "";
                LeaveCriticalSection(&CS);
                //UnLock();
            break;
        }

    }while( brVal );

    return( rVal );
}

MyTest1 und MyTest2 sind nur zwei test-Funktionen, die ich als Reaktion auf einen Knopf drücken. MyTest1 nie ein problem verursacht, egal wie schnell ich auf die Schaltfläche klicke. MyTest2 dead locks fast immer.

//No Dead Lock
void TTest::MyTest1()
{
    if(gdb)
    {
        //else where: gdb = new TGDB;
        gdb->Print(++I);
    }
}


//Causes a Dead Lock
void TTest::MyTest2()
{
    if(gdb)
    {
        //else where: gdb = new TGDB;
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
        gdb->Print(++I);
    }
}

UPDATE:
Einen Fehler gefunden in meinem Ringpuffer-implementation. Unter der schweren Last, als Puffer gewickelt, ich wollte nicht erkennen, die der Puffer voll ist, so richtig Puffer war nicht zurück. Ich bin mir ziemlich sicher, dass Problem ist jetzt gelöst. Sobald ich der festen ring buffer Problem, Leistung viel besser. Wenn ich allerdings die Abnahme der iWaitTime, meine dead lock (oder einfrieren-Problem) gibt.

Also nach weiteren tests mit einer viel schwereren Last es scheint, dass mein deadlock ist nicht verschwunden. Unter super heavy load ich weiter deadlock oder zumindest meine app abstürzt, aber nicht wo in der Nähe, es zu verwenden, da ich der festen ring-Puffer-problem. Wenn ich die doppelte Anzahl an Print-Anrufe in MyTest2 ich einfach sperren können zu jeder Zeit....

Auch, meine aktualisierte code spiegelt sich vor. Ich weiß, dass meine Set & Reset-Ereignis-Anrufe werden innerhalb Kritischer Abschnitt ruft.

  • Offtopic: ich Frage mich, warum der code nicht markieren? In der Bearbeiten-Ansicht... Gut tut es manchmal, sowieso. =/
  • highlights für mich... Vielleicht versuchen Sie, clearing-browser-cache und Neustart?
  • Sie können laufen in einer debugger-rechten? Wo sind die threads, wenn es "deadlocks" ?
  • ja, ich kann laufen, diese in einen debugger und kann ich auch in meinem main-code-Basis, so lange ich keine Treffer mit jeder Art der Belastung; d.h. der Aufruf der TDGB::Print-Methode in eine for-Schleife oder nacheinander. Bitte Lesen Sie meine beiden test-Funktionen (MyTest1 & MyTest2). Im debugger bekomme ich die EnterCriticalSection und hängen.
  • Welche IDE verwendest du in?
  • Die IDE von C++ Builder, Rad XE

InformationsquelleAutor Eric | 2011-02-18
Schreibe einen Kommentar