在Windows CE下,不支持OVERLAPPED I / O.这意味着通过串口的双向通信可能非常麻烦.主要的问题是,当您等待来自串行端口的数据时,您无法发送数据,因为这样做会导致主线程阻塞,直到读取操作完成或超时(取决于您是否设置了超时)
像大多数人一样做串行I / O,我有一个读取器串行线程设置用于读取串行端口,它使用WaitCommEvent()和EV_RXCHAR掩码来等待串行数据.现在,这就是Windows和Windows CE出现问题的地方.
UINT SimpleReaderThread(LPVOID thParam) { DWORD eMask; WaitCommEvent(thParam,&eMask,NULL); MessageBox(NULL,TEXT("Thread Exited"),TEXT("Hello"),MB_OK); }
显然在上面的例子中,我不是从串口或任何东西读取数据而是我假设thParam包含通信端口等的打开句柄.现在,当你的线程执行并且命中时,问题出在Windows下WaitCommEvent(),您的读者线程将进入休眠状态等待串口数据.好的,这很好,应该如此,但是…你如何结束这个线程并让MessageBox()出现?事实证明,它实际上并不那么容易,并且它在执行其串行I / O方面是Windows CE和Windows之间的根本区别.
在Windows CE下,您可以做一些事情来使WaitCommEvent()失效,例如SetCommMask(COMMPORT_HANDLE,0)或甚至CloseHandle(COMMPORT_HANDLE).这将允许您正确终止线程,因此释放串口以便您再次开始发送数据.但是这些东西都不能在Windows下运行,并且两者都会导致你调用它们的线程在WaitCommEvent()完成时等待.那么,你如何结束Windows下的WaitCommEvent()?好吧,通常你会使用OVERLAPPED I / O并且线程阻塞不会成为问题,但由于解决方案必须与Windows CE兼容,因此OVERLAPPED I / O不是一个选项.在Windows下你可以做一件事来结束WaitCommEvent(),那就是调用CancelSynchronousIo()函数,这将结束你的WaitCommEvent(),但要注意这可能是设备依赖的. CancelSynchronousIo()的主要问题是Windows CE也不支持它,所以你运气不好用于解决这个问题!
你是怎么做到的?事实是,要解决此问题,您根本无法使用WaitCommEvent(),因为无法在Windows CE支持的Windows上终止此功能.然后,您将使用ReadFile(),它会在读取NON OVERLAPPED I / O时再次阻塞,这将与Comm Timeouts一起使用.
使用ReadFile()和COMMTIMEOUTS结构意味着您必须有一个紧密循环等待您的串行数据,但如果您没有收到大量的串行数据,它应该不是问题.此外,以小超时结束循环的事件也将确保将资源传递回系统,并且您不会将处理器置于100%负载下.以下是我提出的解决方案,如果您认为可以改进,我会很感激您的反馈意见.
typedef struct { UINT8 sync; UINT8 op UINT8 dev; UINT8 node; UINT8 data; UINT8 csum; } COMMDAT; COMSTAT cs = {0}; DWORD byte_count; COMMDAT cd; ZeroMemory(&cd,sizeof(COMMDAT)); bool recv = false; do { ClearCommError(comm_handle,&cs); if (cs.cbInQue == sizeof(COMMDAT)) { ReadFile(comm_handle,&cd,sizeof(COMMDAT),&byte_count,NULL); recv = true; } } while ((WaitForSingleObject(event_handle,2) != WAIT_OBJECT_0) && !recv); ThreadExit(recv ? cd.data : 0xFF);
因此,要结束线程,您只需在event_handle中发出事件信号,并允许您正确退出线程并清理资源并在Windows和Windows CE上正常工作.
希望能帮助我见过的每个人都遇到这个问题.
解决方法
首先,您可以动态加载CancelSynchonousIo并在操作系统中使用它时使用它.甚至可选择做一些事情而不是取消CE(比如关闭句柄?);
typedef BOOL (WINAPI *CancelIo)(HANDLE hThread); HANDLE hPort; BOOL CancelStub(HANDLE h) { // stub for WinCE CloseHandle(hPort); } void IoWithCancel() { CancelIo cancelFcn; cancelFcn = (CancelIo)GetProcAddress( GetModuleHandle(_T("kernel32.dll")),_T("CancelSynchronousIo")); // if for some reason you want something to happen in CE if(cancelFcn == NULL) { cancelFcn = (CancelIo)CancelStub; } hPort = CreateFile( /* blah,blah */); // do my I/O if(cancelFcn != NULL) { cancelFcn(hPort); } }
另一个选项,需要更多的工作,因为你可能会有不同的线程模型(虽然如果你使用C,它将是基于平台的单独类的一个很好的例子)将是确定平台并在桌面上重叠使用:
HANDLE hPort; void IoWithOverlapped() { DWORD overlapped = 0; OsveRSIONINFO version; GetVersionEx(&version); version.dwOsversionInfoSize = sizeof(OsveRSIONINFO); if((version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) || (version.dwPlatformId == VER_PLATFORM_WIN32_NT)) { overlapped = FILE_FLAG_OVERLAPPED; } else { // create a receive thread } hPort = CreateFile( _T("COM1:"),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,overlapped,NULL); }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。