createevent
createevent 定义:
-
handle WINAPI CreateEvent(
-
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
-
_In_ BOOL bManualReset, //设置信号复位方式为自动恢复为无信号状态(FALSE)还是手动恢复为无信号状态(TRUE)
-
_In_ BOOL bInitialState, //初始状态
-
_In_opt_ LPCTSTR lpName //信号名称,可以为Null
-
);
方式一:
hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); //复位方式为自动恢复到无信号状态,且初始状态为有信号.
此时当使用如下表达式后:
Dword dReturn = WaitForSingleObject(hEvent, 等待时间);
hEvent 就会变为无信号状态,如果在某个时候再次需要上面的式子成立并通过,则需要使用下面的语句使其变为有信号状态(此方式只能解锁一个等待线程,如需继续解锁,则需要再次使用下面的式子)
SetEvent(hEvent)
方式二:
hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); //复位方式为手动恢复到无信号状态,且初始状态为有信号.
此时当使用如下表达式后:
dword dReturn = waitforSingleObject(hEvent, 等待时间);
会自动再次变为有信号状态,上面的式子会直接执行并通过(同时有多个等待线程也会直接执行并通过),如果需要将hEvent设置为无信号状态,则需要手动使用下面的语句:
ResetEvent(hEvent);
注:上面的复位方式指的是恢复到无信号状态的方式,若设置为TRUE,则表示需要手动将其置为无信号,若为FALSE,则会自动变为无信号,千万别和信号量变为有信号状态的方式搞混了!
同步I/O方式打开串口的示例代码:
C++代码
- HANDLE hCom; //全局变量,串口句柄
- hCom=CreateFile("COM1",//COM1口
- GENERIC_READ|GENERIC_WRITE, //允许读和写
- 0, //独占方式
- NULL,
- OPEN_EXISTING, //打开而不是创建
- 0, //同步方式
- NULL);
- if(hCom==(HANDLE)-1)
- {
- AfxmessageBox("打开COM失败!");
- return FALSE;
- }
- return TRUE;
重叠I/O打开串口的示例代码:
C++代码
- HANDLE hCom; //全局变量,串口句柄
- hCom =CreateFile("COM1", //COM1口
- GENERIC_READ|GENERIC_WRITE, //允许读和写
- 0, //独占方式
- NULL,
- OPEN_EXISTING, //打开而不是创建
- FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式
- NULL);
- if(hCom ==INvalid_HANDLE_VALUE)
- {
- AfxMessageBox("打开COM失败!");
- return FALSE;
- }
- return TRUE;
在用ReadFile和WriteFile读写串口时,既可以同步执行,也可以重叠执行。在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。
ReadFile和WriteFile函数是同步还是异步由CreateFile函数决定,如果在调用CreateFile创建句柄时指定了FILE_FLAG_overlapPED标志,那么调用ReadFile和WriteFile对该句柄进行的操作就应该是重叠的;如果未指定重叠标志,则读写操作应该是同步的。ReadFile和WriteFile函数的同步或者异步应该和CreateFile函数相一致。
ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastERROR函数分析返回的结果。例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成。
同步方式读写串口比较简单,下面先例举同步方式读写串口的代码:
//同步读串口
char str[100];
DWORD wCount;//读取的字节数
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,100,&wCount,NULL);
if(!bReadStat) {
AfxMessageBox("读串口失败!");
}
eturn TRUE;
//同步写串口
char lpOutBuffer[100];
DWORD dwBytesWrite=100;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat) {
AfxMessageBox("写串口失败!");
}
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
在重叠操作时,操作还未完成函数就返回。
重叠I/O非常灵活,它也可以实现阻塞(例如我们可以设置一定要读取到一个数据才能进行到下一步操作)。有两种方法可以等待操作完成:一种方法是用象WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员;另一种方法是调用GetOverlappedResult函数等待,后面将演示说明。
在使用ReadFile和WriteFile重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。hEvent是读写事件。当串口使用异步通讯时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。
当调用ReadFile, WriteFile 函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。
GetOverlappedResult函数 BOOL GetOverlappedResult( HANDLE hFile, // 串口的句柄 // 指向重叠操作开始时指定的LPOVERLAPPED lpOverlapped, //OVERLAPPED结构
LPDWORD lpNumberOfBytesTransferred, // 指向一个32位变量,该变量的值返回实际读写操作传输的字节数。
BOOL bWait // 该参数用于指定函数是否一直等到重叠操作结束。 // 如果该参数为TRUE,函数直到操作结束才返回。 // 如果该参数为FALSE,函数直接返回,这时如果操作没有完成, // 通过调用GetLastError()函数会返回ERROR_IO_incomplete。
);
该函数返回重叠操作的结果,用来判断异步操作是否完成,它是通过判断OVERLAPPED结构中的hEvent是否被置位来实现的。
异步读串口的示例代码:
char lpInBuffer[1024];
DWORD dwBytesRead=1024;
COMSTAT ComStat;
DWORD dwErrorFlags;
OVERLAPPED m_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if(!dwBytesRead) return FALSE;
BOOL bReadStatus;
bReadStatus=ReadFile(hCom,lpInBuffer, dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus) //如果ReadFile函数返回FALSE
{
if(GetLastError()==ERROR_IO_PENDING) //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
{
WaitForSingleObject(m_osRead.hEvent,2000); //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟 //当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return dwBytesRead;
} return 0;
}
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return dwBytesRead;
相关阅读
Windows API——CREATEEVENT——创建事件 事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。事件告诉线程何
事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个