Мое Многопоточное Приложение Взбесилось

decay

Member
15.04.2008
6
0
#1
Дописываю программу для работы с несколькими COM-портами. Сделал класс UniThread, и на его базе создал еще 2 класса ReadThread и WriteThread (итого в проге один главный поток и два моих). Все работало хорошо (пока реализации классов ReadThread и WriteThread были в одном модуле с реализацией класса ComPort), затем я выделил эти 2 класса в отдельные модули, немного подправил - и началось...
Посылаю данные в порт, на том конце их ловит микроконтроллер и отвечает эхом. Моя прога считывает их и записывает в консольку на форме (TMemo). Но принимает странно: то правильные данные, то какую-то чушь. Бывает, проскакивает какая-то хрень и в отправляемых данных, но это реже гораздо. Правильно принимает, если не двигать мышкой и не наводить ее на элементы управления формой (кнопки, комбобоксы и проч.). Если навести мышку на консольку TMemo и даже двигать при этом, то тоже работает без сбоев. Подозреваю, какая-то пробема с синхронизацией.

<!--shcode--><pre><code class='#CPP'>int ReadThread::ProcCmds(void)
{
//int RXVal = 0;
unsigned int i=0;
unsigned char TempBuff[MAX_PACKET_LEN];
AnsiString CurrCmd;// = "";
//if (!itsLogFile) return 0;
while ( itsBuff->GetBufLen() >= PacketLen )
{
CurrCmd = "read: ";
for (i=0; i<PacketLen; i++)
{
itsBuff->Read(&TempBuff);
CurrCmd += IntToHex(TempBuff, 2) + " ";
}
//if (itsLogFile != FILE_FAIL) FileWrite(itsLogFile, TempBuff, itsRcvPacketLen);

/*
FormComTerm->mConsoleOut->Lines->Add(CurrCmd);
RXVal = StrToInt(FormComTerm->stRXd->Caption);
FormComTerm->stRXd->Caption = IntToStr(++RXVal);
*/
pConsole->Lines->Add(CurrCmd);
//RXVal = StrToInt(FormComTerm->stRXd->Caption);
//FormComTerm->stRXd->Caption = IntToStr(++RXVal);
}
return 0;
}
//------------------------------------------------------------------------------
DWORD ReadThread::MainFunc(void)
{
unsigned int AvaibleBytes;
unsigned char Buffer[10], RcvCmd[MAX_PACKET_LEN];
unsigned int i=0;//, BytesCnt=0;
DWORD dwWaitMutex, dwWaitPort;
DWORD Mask, RealRead, BytesTrans, Err;
OVERLAPPED ReadOL;
AnsiString CurrCmd = "read: ";
COMSTAT OwnersState;

memset(&ReadOL,0,sizeof(ReadOL));
ReadOL.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
SetCommMask(itsOwnersHandle , EV_RXCHAR);

while(!m_bTerminated)
{
//if ( !(itsOwner->Connected) ) goto finish; //hernya
if (itsOwnersHandle == NULL) return false;

WaitCommEvent(itsOwnersHandle, &Mask, &ReadOL);
dwWaitPort = WaitForSingleObject(ReadOL.hEvent, INFINITE);
if (dwWaitPort == WAIT_OBJECT_0)
{
if ( GetOverlappedResult(
itsOwnersHandle,
&ReadOL,
&BytesTrans,
FALSE)
)
{
if ((Mask & EV_RXCHAR))
{
ClearCommError (
itsOwnersHandle,
&Err,
&OwnersState
);
AvaibleBytes = OwnersState.cbInQue;
ReadFile(
itsOwnersHandle,
&Buffer,
AvaibleBytes,
&RealRead,
&ReadOL
);
i=0;
while (i<RealRead)
{
dwWaitMutex = WaitForSingleObject(PortMutex,INFINITE);
switch (dwWaitMutex)
{
case WAIT_OBJECT_0:
itsBuff->Write(Buffer);
ProcCmds();

//BytesCnt = 0;
if ( !ReleaseMutex(PortMutex) )
{
//ShowMessage("STOP thrd2");
}
break;
case WAIT_ABANDONED:
//cout << "aband ";
//the resource is busy, let's try it again at next time
break;
default:
//ReleaseMutex(itsOwner->hMutex)
//cout << "default ";
//break;
;
}
i++;
}
}
//RcvCnt += RealRead;
}
}
Sleep(1);
}
return 0;
}[/CODE]

Помогите разобраться с проблемой!
 

decay

Member
15.04.2008
6
0
#2
Потихоньку разбираюсь. В комментах борландовсокого класса TThread написано:

// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(&UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall Thread::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }

А я использую самописный класс потока. Для синхронизации с объектами VCL у меня служит мьютекс hMutex. Позволительно ли это? Не здесь ли корень всех моих проблем?
Но тогда странно, почему раньше работало, а при внесении небольших изменений перестало. Мьютекс создается и используется, я проверял. Что вызывает подозрение - так это содержание считанных с порта в буфер данных. Оно изначально неверное. Эта функция
<!--shcode--><pre><code class='#CPP'>AvaibleBytes = OwnersState.cbInQue;
ReadFile(
itsOwnersHandle,
&Buffer,
AvaibleBytes,
&RealRead,
&ReadOL
);[/CODE]
возвращает в переменную буфер совсем не то, что надо..Тогда причем здесь синхронизация?

И да! Вот объявление класса UniThread, наследником которого является ReadTHread.
<!--shcode--><pre><code class='#CPP'>class UniThread
{
friend DWORD WINAPI ThreadProc(LPVOID lpParam);
HANDLE itsHandle;
public:
DWORD Terminate(BOOL bCritical = false);
BOOL ExecThread();
UniThread(const char *ThreadLabel, HANDLE hOwner, HANDLE extMutex);
virtual ~UniThread(); //
//void SetPacketLen(unsigned int PackLen);
//void SetPacketsToTransceive(int PackToTrcv, char *pBuff);
char GetStatus(void);

protected:
TMemo *pConsole;
unsigned int PacketLen;
int PacketsToTransceive;


HANDLE PortMutex;
HANDLE itsOwnersHandle;
DWORD itsID;
virtual DWORD MainFunc()=NULL;
BOOL m_bTerminated; //need to terminate flag
//debug
const char *itsLabel;
};[/CODE]
 

-master-

Well-Known Member
14.01.2012
616
20
#3
Из доп потока обращаться к вкл нельзя, нужна синхронизация.
 
#4
На вопрос ответили, но есть замечание в догонку. Зачем для синхронизации потоков внутри приложения Вы используете мьютекс? Для этого существует более быстрая критическая секция. Мьютекс нужен для синхронизации потоков между разными приложениями.