Having what seems like a deadlock situation with a multi-threaded logging application.
Little background:
My main application runs 4-6 threads. The main thread responsible for monitoring the health of various things that I perform, updating the GUI, etc. Then I have a transmit stream and a receive stream. Transmission and reception streams refer to physical equipment. Sometimes I have to debug data that sees transmit and receive streams; those. print to the console without interrupting them due to their critical nature of the data. The data, by the way, is on the USB bus.
Due to the multithreading of the application, I want to create a debug console with which I can send messages from my other threads. The debug pipeline acts as a low-priority stream and implements a ring buffer, so when printed to the debug console, the message is quickly stored in the ring buffer and sets and events. The debug console thread responds to WaitingOnSingleObject events from incoming messages. When an event is detected, the console thread updates the GUI with the message. Just huh? Print calls and console flow use a critical section to control access.
NOTE. I can adjust the size of the ring buffer if I see that I am deleting messages (at least this idea).
, . , , . , - ( Print), . , IDE EnterCriticalSection .
. Lock/UnLock Enter/LeaveCriticalSection (. ), , . push/pops, Enter/LeaveCriticalSection , ... ?
Print, int .
void TGDB::Print(int I)
{
EnterCriticalSection(&CS);
if( !SuppressOutput )
{
sprintf( MsgRec->Msg, "%d", I);
MBuffer->PutMsg(MsgRec, 1);
}
SetEvent( m_hEvent );
LeaveCriticalSection(&CS);
}
void TGDB::Lock(void)
{
EnterCriticalSection(&CS);
}
bool TGDB::TryLock(void)
{
return( TryEnterCriticalSection(&CS) );
}
void TGDB::UnLock(void)
{
LeaveCriticalSection(&CS);
}
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);
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);
break;
case WAIT_TIMEOUT:
EnterCriticalSection(&CS);
Info->Caption = "Idle";
Info->Refresh();
brVal = KeepRunning;
ResetEvent( m_hEvent );
LeaveCriticalSection(&CS);
break;
case WAIT_FAILED:
EnterCriticalSection(&CS);
brVal = false;
Info->Caption = "ERROR";
Info->Refresh();
aLine.sprintf("Console error: [%d]", GetLastError() );
Log->Lines->Add(aLine);
aLine = "";
LeaveCriticalSection(&CS);
break;
}
}while( brVal );
return( rVal );
}
MyTest1 MyTest2 - , . MyTest1 , . MyTest2 .
void TTest::MyTest1()
{
if(gdb)
{
gdb->Print(++I);
}
}
void TTest::MyTest2()
{
if(gdb)
{
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:
. , , , . , . , . , iWaitTime, ( ) .
, , , . , , , , , . Print MyTest2, ....
, . , Set Reset .