C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Синхронизация потоков при работе с портом, потоки читают чужую инфу...
bred
Отправлено: 19.01.2007, 15:49


Ученик-кочегар

Группа: Участник
Сообщений: 15



Формы MDI-приложения обращаетюся к устройству через ком-порт. т.е. они создают потоки (когда надо) выполнения какой-либо команды и слушают ответ от этих потоков.
Есть функция записи команды(любой как парметр) в девайс (порт) и вычитывания ответа. Весь процес записи ожидания ответа и его чтения закрыт критической секцией. Разные потоки пытаются выполнять различные команды на девайсе. И время от времени в качестве ответа получают совсем не свои данные. Пробовал обращение закрыть мьютексом — та же ситуация.
CODE

//-----------------------------------------------------------------------------
// Чтение из порта
// Out  — команда на посылку
// Input — приемный буффер
// Flags — управляющие флаги
//-----------------------------------------------------------------------------
DWORD ReadFromPort( LPBYTE Out, LPBYTE Input, DWORD Flags, HANDLE Mutex)
{
DWORD Read = 0;
int InNum = 0;
int Length = strlen(Out);

if( 0 == (Flags & fNO_NEED_COM_BUSY ) )
if( ( COMM_NOT_DEVICE == fComBusy ) || ( COMM_NOT_INIT == fComBusy ) )
return fComBusy;

if ( false == MainForm->ComPort->Connected )
return PORT_ERROR_HANDLE;

// надо занять порт
if( 0 == (Flags & fNEED_COM_MUST_OPEN ) )
{
// EnterCriticalSection(&port_sect_blok);
WaitForSingleObject( Mutex , INFINITE );
/*while ( COMM_NOT_BUSY != fComBusy )
Sleep(1);
fComBusy = COMM_BUSY;*/
}
// очистка буфера
MainForm->ComPort->ClearBuffer( true, true );
Sleep(SLEEP_TIME_TO_CLEAR);
MainForm->ComPort->ClearBuffer( true, true ); // зачистка буфферов
// послать комманду
MainForm->ComPort->Write( Out , Length );
Sleep(SLEEP_TIME_TO_READ);
InNum = MainForm->ComPort->InputCount();
if ( 0 >= InNum ) // а читать-то нечего
{
if( 0 == (Flags & fNEED_COM_MUST_OPEN ) )
ReleaseMutex(Mutex);
//fComBusy = COMM_NOT_BUSY;
// LeaveCriticalSection(&port_sect_blok);

return WARNING_NOT_DATA_FOR_READ;
}
// читаем из порта пока есть возможность
while ( ( 0 < InNum ) && ( SIZE_COM_BUFFER > (Read + InNum) ) )
{
Read += MainForm->ComPort->Read( Input + Read, InNum );
Sleep(SLEEP_TIME_TO_READ);
InNum = MainForm->ComPort->InputCount();
}
if( 0 == (Flags & fNEED_COM_MUST_OPEN ) )
ReleaseMutex(Mutex);
//fComBusy = COMM_NOT_BUSY;
//LeaveCriticalSection(&port_sect_blok);
if ( 0 < Read ) // убираем эхо
{
if( 0 == memcmp( Input, Out, Length) )
{
Read -= Length;
memmove( Input, Input + Length , Read );
}
}
// наличие признака корректности команды
if( Read > 2)
{
if( 0 == memcmp( Input + Read — 4, END_RECIVE_DATA, 2) )
{
Input[Read — 4 ] = Input [ Read — 2];
Input[Read — 3 ] = Input [ Read — 1];
Input[Read — 2 ] = 0;
Read -=2;// удаление признака корректности комманды
}
else
{
if( true == WantOkAnswer)
return WARNING_READ_NOT_COMPL;
}
}
else
{
if( true == WantOkAnswer)
return WARNING_READ_NOT_COMPL;
}
// проверка наличия КС если должна быть
if( 0 != (Flags & fNEED_CHEK_SUMM_RECIVE ) )
{
if(Read > 3)
{
if ( Input[Read — 3] != ChekSumm( Input, Read — 3) )
{
if( 0 != (Flags & fNEED_HEX_TO_BYTE ) )
Read = HexToBYTE( Input, Read — 3);
return ERROR_CHEK_SUMM_RECIVE;
}
Read -= 3;// удаление \n\r и КС
}
else
{
if( 0 != (Flags & fNEED_HEX_TO_BYTE ) )
Read = HexToBYTE( Input, Read );
return ERROR_CHEK_SUMM_RECIVE;
}
}
// преобразование в хекс
if( 0 != (Flags & fNEED_HEX_TO_BYTE ) )
Read = HexToBYTE( Input, Read);

return Read;
} // чтение

потоки создаются с помощью CreateThread(...);
критическая секция была глобальной (текущий код использует мьютекс и она удалена) и инициализировалась в конструкторе главной формы.
в общих чертах тело потока:
CODE

//------------------------------------------------------------------------------
// поток чтения визуализации
// PORT_MUTEX — продефианеная строка с именем мутекса
//------------------------------------------------------------------------------
DWORD WINAPI WisualisationFuncRead(LPVOID ptr)
{
HANDLE Events[3];
HANDLE Mutex = CreateMutex(NULL,false, PORT_MUTEX);
int Errors = 0;
int Last[10] = { 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 };
int LastBound[10] = { 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 };
int* pEnvelope[10];
int pBound[ NUM_BOUND_OSCILOSCOPE ];
BYTE ForFile[ 16 ][NUM_BYTE_RECIVE_OSCILOSCOPE];
LPBYTE Input = ForFile[0];
LPBYTE FFWrite = ForFile[0];
LPGoThreadReturn SendData = (LPGoThreadReturn)ptr;
int i = 0;
for (i = 0; i < 10; i++)
{
pEnvelope[i] = new int[(EnvelopeSize[i-1])+2];
}
memset( ForFile, 0, NUM_BYTE_RECIVE_OSCILOSCOPE * 15);
Events[0] = CreateEvent( NULL, false, false, OSCILOSCOPE_GO_THREAD_NAME);
Events[1] = CreateEvent( NULL, false, false, TERMINATE_OS_EVENT_THREAD_NAME);
Events[2] = CreateEvent( NULL, false, false, SUSPEND_VISUAL_EVENT_THREAD_NAME);
HANDLE PlotForm; // типа хандл для посылки мессаджа
for (i=0; i<MainForm->MDIChildCount; i++)
{
if (MainForm->MDIChildren[i]->Caption == VISUALISATION_FORM_CAPTION)
{
PlotForm = MainForm->MDIChildren[i]->Handle;
break;
}
}
DWORD retcode = 0;
do
{
retcode = WaitForMultipleObjects( 3, Events, false, GO_SEND_INTERVAL);
if( WAIT_OBJECT_0 + 2 == retcode ) // Suspend
{
ContinueWrite = false;
retcode = WaitForMultipleObjects( 2, Events, false, INFINITE);
}
if( ( WAIT_OBJECT_0 == retcode ) || ( WAIT_TIMEOUT == retcode ) )
{ // либо время вышло либо юзер потребовал
DWORD Read;
BYTE Out[] = {
SendData->Adr, // adr
'G','O', // command
SendData->Chanel, // chanel
0,0
};
Read = ReadFromPort( Out, Input, 0, Mutex);
if( ( 2058 > Read ) || (((Input[2058]&0xFC)!=0xFC)&&((Input[2058]|0x3)!=0x03)) )
{
if( Errors == Max_Num_Error_Read )
{
PostMessage( PlotForm, WND_SAS_READ_GO_OSCIL, 1 , Read );
}
else
{
Errors++;
SetEvent(Events[0]);
}
continue;
}

.....
различная обработка вычитанных данных, с проверкой их корректности, и занесение их в поля SendData
......
Errors = 0;
.....
вывод в файл
.....

PostMessage( PlotForm, WND_SAS_READ_GO_OSCIL, 0 , Read );
}// if not Terminate
} // while
while( (WAIT_OBJECT_0 + 1) != retcode );

for( i = 0; i < 3; i++)
CloseHandle(Events[i]);
for (i = 0; i < 10; i++)
{
delete[] pEnvelope[i]; //pEnvelope[i-1] + EnvelopeSize[i-1];
}
CloseHandle(Mutex);
return 0;
} // поток чтения
вроде ничего важного не выкинул.
Другие потоки вообще строго разбирают по switch case ответ от функции чтения.
В результате потоки не ругаются, что они прочитали не все или наоборот больше, а ругаются на некорректность данных

Отредактировано bred — 19.01.2007, 15:59
bred
Отправлено: 24.01.2007, 17:18


Ученик-кочегар

Группа: Участник
Сообщений: 15



вопрос, кажется решился. Похоже ответный девайс врет.

Вернуться в Вопросы программирования в C++Builder