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

Тема в разделе "Borland C++ Builder & Kylix", создана пользователем decay, 16 май 2013.

  1. decay

    decay Member

    Регистрация:
    15 апр 2008
    Сообщения:
    6
    Симпатии:
    0
    Дописываю программу для работы с несколькими 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]

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

    decay Member

    Регистрация:
    15 апр 2008
    Сообщения:
    6
    Симпатии:
    0
    Потихоньку разбираюсь. В комментах борландовсокого класса 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]
     
  3. -master-

    -master- Well-Known Member

    Регистрация:
    14 янв 2012
    Сообщения:
    629
    Симпатии:
    19
    Из доп потока обращаться к вкл нельзя, нужна синхронизация.
     
  4. Serge78rus

    Serge78rus New Member

    Регистрация:
    26 май 2014
    Сообщения:
    4
    Симпатии:
    0
    На вопрос ответили, но есть замечание в догонку. Зачем для синхронизации потоков внутри приложения Вы используете мьютекс? Для этого существует более быстрая критическая секция. Мьютекс нужен для синхронизации потоков между разными приложениями.
     
Загрузка...

Поделиться этой страницей