jerrywky 2019-07-18 20:07 采纳率: 0%
浏览 823
已采纳

异步方式串口 死循环读取线程 如何退出?

用VC2015写了一个SDI程序,在app类的InitInstance()函数总,开启了一个串口读指令线程(异步方式)。对于串口的操作,比如读、写、配置、清理缓存等等,全部封装在了一个DLL中。
读线程中,用一个BOOL型的开关变量制造了一个死循环,以便实时接收串口收到的数据。同时,也希望在需要终止该线程的时候,将开关量置反,结束死循环。
已知:读指令函数中,会持续监测串口事件,当检测到有数据时,即读取数据。完整数据的读取,是通过GetOverlappedResult函数实现的。
现在的问题是:要关闭进程了(点击文件菜单上的“退出”),在APP类的ExitInstance()函数中置反上述开关量,并且用PurgeComm 刷新串口(使用了PURGE_TXABORT 、PURGE_RXABORT、PURGE_TXCLEAR、PURGE_RXCLEAR四个组合值作为该函数的参数),希望产生串口事件,使待函数WaitCommEvent能够返回,进而在再次循环的时候,对开关量进行判断,因为该开关量已经置反,从而达到结束循环,退出退出线程的目的。
奇怪的是:PurgeComm函数,总是返回不成功,读线程始终结束不了。
本人为新手,不懂的太多,还望高手给与指点!非常感谢!
读线程代码如下:

////worker thread.to receive  instruction from control board.///////
typedef CString(*FuncReceiveFromBoard)(HANDLE, char*);
//int panelFlushSerialPort(HANDLE h)
typedef int(*FuncFlush232)(HANDLE);
FuncReceiveFromBoard ReceiveFromBoard;
FuncFlush232 Flush232;
HINSTANCE hDll_232DLL_RE;
char* pbufcmd = nullptr;
UINT ReceiveInstructionFromBoard(LPVOID pParam)
{
    CDEMODVView *pDemoView1 = (CDEMODVView *)pParam;    
    pbufcmd=nullptr;
    pbufcmd = (char *)malloc(sizeof(char)*253); //分配内存
    memset(pbufcmd, 0, 253);    //将分配给pcmbuf的内存初始化为0
    if (theApp.communi_state == FALSE)  //说明232串口没有配置好或者没有打开
        return 1;
    else
    {
        ReceiveFromBoard = (FuncReceiveFromBoard)GetProcAddress(theApp.hDll_232com, "panelReceiveCmdFromCBoard");   //获取函数theApp.hDll_232com
        Flush232 = (FuncFlush232)GetProcAddress(theApp.hDll_232com, "panelFlushSerialPort");
        if (!ReceiveFromBoard|| !Flush232)
        {
            AfxMessageBox(_T("获取函数失败"));
            return 1;
        }
        else
        {
            CString resStrFromB;    //接收指令字符串
            while (theApp.m_threadrunning==TRUE)
            {
                AfxMessageBox(_T("I am going"));
                resStrFromB = ReceiveFromBoard(theApp.hDleopen, pbufcmd);   
                //用DLL中接收函数得到指令字符串给resStrFromB
                if (resStrFromB !=_T(""))//
                {                   
                    pDemoView1->m_strInstruction2Recive = resStrFromB;
                    pDemoView1->SendMessage(WM_INSTRUCTION_RECEIVE);    //给VIEW类发送接收到字符串的消息
                    resStrFromB = _T("");
                    Flush232(theApp.hDleopen);
                    //Sleep(4000);
                }

            }
//          设置线程等待函数已经退出循环,可以结束的标志;
            theApp.m_threadstop = TRUE;
        }
    }
    free(pbufcmd);
    pbufcmd = nullptr;  
    return 0;
}

前述封装的对串口操作的DLL中,关于读文件的部分,代码如下:

DWORD __stdcall ReadCmdSerialPort(HANDLE h, char * const pszBuf, DWORD bufSize, DWORD *dwSize, DWORD *dwEventMask)
{
    DWORD error = ERROR_SUCCESS;
    memset(&overread, 0, sizeof(OVERLAPPED));   
    overread.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    //创建overlapped事件:句柄不能被继承,人工重置事件,初始状态为无信号,匿名事件
    DWORD dwError;  
    COMSTAT comstat;    
    ClearCommError(h, &dwError, &comstat);  
    //清除端口错误
    if (!SetCommMask(h, EV_BREAK | EV_ERR | EV_RXCHAR | EV_RXFLAG)) /* Setting Event Type */
    {
        /*printf("$\n");*/
        return ::GetLastError();
    }

    if (!WaitCommEvent(h, dwEventMask, &overread)) /* Waiting For Event to Occur */
    {
        DWORD dwIncommingReadSize;
        if (GetLastError() == ERROR_IO_PENDING)
        {
            GetOverlappedResult(h, &overread, &dwIncommingReadSize, TRUE);
            // 等待异步操作结束后才返回到应用程序,此时,GetOverlappedResult函数与WaitForSingleObject函数等效
            switch (*dwEventMask)
            {
            case EV_BREAK:
                _snprintf_s(pszBuf, bufSize, _TRUNCATE, "BREAK received");
                /*printf("*\n");*/
                return error;
                break;
            case EV_ERR:
                _snprintf_s(pszBuf, bufSize, _TRUNCATE, "Line status error occurred");
                /*printf("&\n");*/
                return error;
                break;
            case EV_RXFLAG:
                return error;
                break;
            case EV_RXCHAR:
            {
                char szBuf;
                //DWORD dwIncommingReadSize;
                *dwSize = 0;
                unsigned int ndx = 0;
                do
                {
                    // 读取数据:指定读取的字节数为1,dwIncommingReadSize:读到的字节数;异步读取
                    if (ReadFile(h, &szBuf, 1, &dwIncommingReadSize, &overread) != 0)   //
                    {
                        if (dwIncommingReadSize > 0)
                        {
                            *dwSize += dwIncommingReadSize;
                            if (ndx < bufSize - 1)
                            {
                                pszBuf[ndx] = szBuf;
                                ndx += dwIncommingReadSize;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }

                } while (dwIncommingReadSize > 0);
                ResetEvent(overread.hEvent);// 释放事件句柄                                       
                return error;
                break;
            }               
            default:
                _snprintf_s(pszBuf, bufSize, _TRUNCATE, "unknown COMM event");
                return error;
                break;
            }
            ResetEvent(overread.hEvent);// 释放事件句柄  
        }
        else
        {
            return ::GetLastError();
        }
    }
}
  • 写回答

2条回答 默认 最新

  • dabocaiqq 2019-07-18 20:33
    关注
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 (关键词-电路设计)
  • ¥15 如何解决MIPS计算是否溢出
  • ¥15 vue中我代理了iframe,iframe却走的是路由,没有显示该显示的网站,这个该如何处理
  • ¥15 操作系统相关算法中while();的含义
  • ¥15 CNVcaller安装后无法找到文件
  • ¥15 visual studio2022中文乱码无法解决
  • ¥15 关于华为5g模块mh5000-31接线问题
  • ¥15 keil L6007U报错
  • ¥15 webapi 发布到iis后无法访问
  • ¥15 初学者如何快速上手学习stm32?