Чтение COM-порта - поток остается активным после истечения времени ожидания - PullRequest
0 голосов
/ 29 декабря 2010

У меня есть DLL, которая включает в себя функцию ReadPort, которая читает данные из последовательного COM-порта, написанного на c / c ++. Эта функция вызывается в дополнительном потоке из другой функции WINAPI, используя _beginthreadex. Когда COM-порт имеет данные для чтения, рабочий поток возвращает данные, обычно завершается, вызывающий поток закрывает дескриптор рабочего потока, и DLL работает нормально.

Однако, если ReadPort вызывается без данных, ожидающих на COM-порте, то по истечении времени ожидания WaitForSingleObject возвращает WAIT_TIMEOUT, но рабочий поток никогда не заканчивается. В результате виртуальная память увеличивается примерно на 1 МБ каждый раз, физическая память увеличивается на несколько КБ, и приложение, которое вызывает dll, становится нестабильным. Я также попытался использовать TerminateThread (), но получил те же результаты.

Я должен признать, что, хотя у меня достаточно опыта разработки, я не знаком с c / c ++. Я провел много исследований до публикации, но, к сожалению, мне не удалось решить мою проблему.

Кто-нибудь знает, как я могу решить эту проблему? Однако я действительно хочу придерживаться такого решения. Кроме того, я хочу упомянуть, что я думаю, что не могу использовать какие-либо глобальные переменные для использования каких-то дополнительных событий, потому что функции каждой библиотеки DLL могут вызываться много раз для каждого COM-порта.

Я публикую некоторые части своего кода ниже:

Рабочая тема:

unsigned int __stdcall ReadPort(void* readstr){

DWORD  dwError; int   rres;DWORD  dwCommModemStatus, dwBytesTransferred;
int ret;
char szBuff[64] = "";

ReadParams* params = (ReadParams*)readstr;

ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
if (ret == 0)
{
    _endthreadex(0);
    return -1;
}
ret = WaitCommEvent(params->param2, &dwCommModemStatus, 0);
if (ret == 0)
{
    _endthreadex(0);
    return -2;
}
ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD| EV_RING);
if (ret == 0)
{
    _endthreadex(0);
    return -3;
}

if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
    rres = ReadFile(params->param2, szBuff, 64, &dwBytesTransferred,NULL);
    if (rres == 0)
    {
        switch (dwError = GetLastError())
        {
            case ERROR_HANDLE_EOF:
            _endthreadex(0);
            return -4;
        }

        _endthreadex(0);
        return -5;
    }
    else
    {
        strcpy(params->param1,szBuff);
        _endthreadex(0);
        return 0;
    }
}
else
{
    _endthreadex(0);
    return 0;
}
_endthreadex(0);
return 0;}

Вызывающая нить:

int WINAPI StartReadThread(HANDLE porthandle, HWND windowhandle){

HANDLE hThread;
unsigned threadID;
ReadParams readstr;
DWORD ret, ret2;

readstr.param2 = porthandle;

hThread = (HANDLE)_beginthreadex( NULL, 0, ReadPort, &readstr, 0, &threadID );
ret = WaitForSingleObject(hThread, 500);

if (ret == WAIT_OBJECT_0)
{
    CloseHandle(hThread);  
    if (readstr.param1 != NULL)
        // Send message to GUI
    return 0;
}
else if (ret == WAIT_TIMEOUT)
{
    ret2 = CloseHandle(hThread);
    return -1;
}
else
{
    ret2 = CloseHandle(hThread);
    if (ret2 == 0)
    return -2;
}}

Заранее спасибо,

Sna.

Ответы [ 3 ]

1 голос
/ 30 декабря 2010

Измените задержку при вызове WaitForSingleObject на 5000 или 10000, и я уверен, что частота ваших проблем значительно снизится.

Ответ Эдвина также действителен.Появившаяся нить не умирает, потому что вы закрыли дескриптор нити.

Нет никакой гарантии, что нить ReadPort даже запустилась к тому времени, когда вы истекаете.Windows занимает ДОЛГОЕ время, чтобы запустить поток.

Вот несколько советов:

  • Вы никогда не проверяете возвращаемое значение beginthreadex.Откуда вы знаете, что поток запущен?

  • Используйте любой метод синхронизации, с которым вам удобно синхронизировать запуск потока ReadPort с StartReadThread.Это может быть просто целочисленный флаг, который ReadPort устанавливает в 1, когда он готов к работе.Тогда основной поток может начать свое истинное ожидание в этой точке.В противном случае вы никогда не узнаете, если не используете отладчик, что происходит между двумя потоками.Не превышайте время ожидания вызова WaitForSingleObject в StartReadThread, пока ваш метод синхронизации не покажет, что ReadPort работает.

  • Вы не должны использовать strcpy для копирования байтовполученный от последовательного порта с ReadFile.ReadFile говорит вам, сколько байтов прочитано.Используйте это значение и memcpy для заполнения буфера.

  • Посмотрите здесь и здесь для получения информации о том, как иметь ReadFile времятак что ваши чтения не являются неопределенными.Блокирование навсегда в Windows - это путь к катастрофе, поскольку он может вызвать процессы зомби, которые вы не можете уничтожить, среди других проблем.

  • Вы не сообщаете StartReadThread о том, что произошло в ReadPort нить.Как узнать, сколько байтов ReadPort помещено в szBuff?Чтобы получить код выхода из theads, используйте GetExitCodeThread.Документировано здесь .Обратите внимание, что вы не можете использовать GetExitCodeThread, если закрыли ручку нити.

1 голос
/ 30 декабря 2010

Не используйте WaitCommEvent. Вы можете позвонить ReadFile, даже если нет ожидающих данных.

Используйте SetCommTimeouts, чтобы сделать ReadFile само по себе тайм-аутом, вместо того, чтобы строить тайм-аут по связи между потоками.

0 голосов
/ 29 декабря 2010

В вашей вызывающей ветке по истечении времени ожидания вы закрываете ручку цепочки.Это только остановит вас от использования ручки.Однако рабочий поток все еще работает.Вы должны использовать цикл, который ждет снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...