异步设备IO 《windows核心编程》第10章学习
异步IO操作与同步操作区别:
- 在CreateFile里的FILE_FLAG_OVERLAPPED标志
- 异步操作函数LPOVERLAPPED参数
接收IO请求完成通知
- 触发设备内核对象
缺点:同一个设备内核对象有可能进行多次读写操作,这样第一个完成这个设备内核对象就会被触发,所以这种方式不可以使用于这种情形void Test1()
{
HANDLE hFile = ::CreateFile(_T("aaa.txt"),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if(!hFile)
{
wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl;
return ;
}
DWORD dwFileSize = ::GetFileSize(hFile,);
wcout<<L"FileSize:"<<dwFileSize<<endl;
char * pFileContent = new char[];
DWORD dwReaded = ;
OVERLAPPED o_Read = {};
DWORD bReadDone = ::ReadFile(hFile,
pFileContent,
,
&dwReaded,
&o_Read);
DWORD dwError = ::GetLastError();
if(!bReadDone && (dwError == ERROR_IO_PENDING))
{
WaitForSingleObject(hFile,INFINITE);
bReadDone = TRUE;
} if(bReadDone)
wcout<<L"I/O Code:"<<o_Read.Internal<<" TransedBytes:"<<o_Read.InternalHigh<<endl;
else
wcout<<"Error:"<<::GetLastError()<<endl;
::CloseHandle(hFile);
delete [] pFileContent;
} - 触发事件内核对象
void Test2()
{
HANDLE hFile = ::CreateFile(_T("aaa.txt"),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if(!hFile)
{
wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl;
return ;
}
DWORD dwFileSize = ::GetFileSize(hFile,);
wcout<<L"FileSize:"<<dwFileSize<<endl;
LARGE_INTEGER liDis = {};
LARGE_INTEGER liRet = {};
::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
char * pFileContent = new char[];
memset(pFileContent,'z',);
DWORD dwReaded = ;
OVERLAPPED o_Write = {};
o_Write.Offset = liRet.LowPart;
o_Write.hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
DWORD bReadDone = ::WriteFile(hFile,
pFileContent,
,
&dwReaded,
&o_Write);
DWORD dwError = ::GetLastError();
if(!bReadDone && (dwError == ERROR_IO_PENDING))
{
WaitForSingleObject(o_Write.hEvent,INFINITE);
bReadDone = TRUE;
} if(bReadDone)
wcout<<L"I/O Code:"<<o_Write.Internal<<" TransedBytes:"<<o_Write.InternalHigh<<endl;
else
wcout<<"Error:"<<::GetLastError()<<endl;
::CloseHandle(hFile);
delete [] pFileContent;
} - 可提醒IO
void Test3()
{
//可提醒IO
HANDLE hFile = ::CreateFile(_T("aaa.txt"),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if(!hFile)
{
wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl;
return ;
}
DWORD dwFileSize = ::GetFileSize(hFile,);
wcout<<L"FileSize:"<<dwFileSize<<endl;
LARGE_INTEGER liDis = {};
LARGE_INTEGER liRet = {};
::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
char * pFileContent = new char[];
memset(pFileContent,'g',);
DWORD dwReaded = ;
OVERLAPPED o_Write = {};
o_Write.Offset = liRet.LowPart;
DWORD bReadDone = ::WriteFileEx(hFile,
pFileContent,
,
&o_Write,
FileIOCompletionRoutine); ::CloseHandle(hFile);
SleepEx(,TRUE);
delete [] pFileContent;
}可提醒IO的优劣:
(1)由于回调函数的原因,最终不得不把大量信息放在全局变量中。使代码变的更加复杂
(2)发出请求线程和完成处理必须是同一线程,没有达到线程负载均衡
可提醒IO相关函数
(1)QueueUserAPC函数
a.这个函数允许我们手动增加APC项。
b.可以强制线程退出等待状态比如WaitForSingleObjectEx 以下是示例代码
VOID WINAPI APCFunc(ULONG_PTR pvParam)
{
//Nothing To Do
} UINT WINAPI ThreadFunc(PVOID pvParam)
{
wcout<<L"start Wait...."<<endl;
DWORD dw = ::WaitForSingleObjectEx(pvParam,INFINITE,TRUE);
if(dw == WAIT_OBJECT_0)
{
wcout<<L"Event signaled"<<endl;
return ;
}
else if(dw == WAIT_IO_COMPLETION)
{
wcout<<L"QueueUserApc Forced us out of a wait state"<<endl;
return ;
}
return ;
}
void Test4()
{
//利用QueueUserApc来停止线程等待
HANDLE hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE hThread = (HANDLE) _beginthreadex(NULL,,ThreadFunc,hEvent,,NULL);
Sleep();
QueueUserAPC(APCFunc,hThread,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hEvent);
} - I/O完成端口
待续void Test5()
{
//I/O完成端口
TCHAR SrcFileName[MAXSIZE];
TCHAR DesFileName[MAXSIZE]; cout<<"请输入源文件名:\n";
wcin>>SrcFileName; cout<<"请输入目的文件名:\n";
wcin>>DesFileName; HANDLE hSrcFile=CreateFile(SrcFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_FLAG_OVERLAPPED,NULL);
if(hSrcFile==INVALID_HANDLE_VALUE)
{
printf("文件打开失败!");
}
DWORD FileSizeHigh;
DWORD FileSize=GetFileSize(hSrcFile,&FileSizeHigh); HANDLE hDstFile=CreateFile(DesFileName,GENERIC_WRITE,,NULL,CREATE_NEW,FILE_FLAG_OVERLAPPED,NULL); //创建完成端口
HANDLE hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,,);
if(hIOCP==NULL)
{
printf("完成端口创建失败!");
} //绑定完成端口
CreateIoCompletionPort(hSrcFile,hIOCP,READ_KEY,);
CreateIoCompletionPort(hDstFile,hIOCP,WRITE_KEY,); OVERLAPPED ov={};
PostQueuedCompletionStatus(hIOCP,,WRITE_KEY,&ov);
OVERLAPPED ovSrc={};
OVERLAPPED ovDes={};
ULONG_PTR CompletionKey;
BYTE* pBuffer=new BYTE[BUFFERSIZE];
int i=;
int j=;
while(true)
{
DWORD nTransfer;
OVERLAPPED* o; GetQueuedCompletionStatus(hIOCP,&nTransfer,&CompletionKey,&o,INFINITE);
switch(CompletionKey)
{
case READ_KEY:
//代表读取IO操作已经完成,进行下一步写入操作
WriteFile(hDstFile,pBuffer,o->InternalHigh,NULL,&ovDes);
cout<<"write:"<<++i<<endl;
ovDes.Offset+=o->InternalHigh;
//if(ovDes.Offset== FileSize/1024 )
// return 0;
break;
case WRITE_KEY:
//代表写入IO操作已经完成,进行下一步读取操作
memset(pBuffer,,BUFFERSIZE*sizeof(BYTE));
if(ovSrc.Offset < FileSize)//文件读取未完成
{
DWORD nBytes;
if(ovSrc.Offset+BUFFERSIZE < FileSize)
nBytes=BUFFERSIZE;
else
nBytes=FileSize-ovSrc.Offset;
ReadFile(hSrcFile,pBuffer,nBytes,NULL,&ovSrc);
cout<<"read:"<<++j<<endl; ovSrc.Offset+=nBytes;
}
else
return ;
break;
default:
break; }
} return ;
}
异步设备IO 《windows核心编程》第10章学习的更多相关文章
- windows核心编程 第8章201页旋转锁的代码在新版Visual Studio运行问题
// 全局变量,用于指示共享的资源是否在使用 BOOL g_fResourceInUse = FALSE; void Func1() { //等待访问资源 while(InterlockedExcha ...
- windows核心编程 第5章job lab示例程序 解决小技巧
看到windows核心编程 第5章的最后一节,发现job lab例子程序不能在我的系统(win8下)正常运行,总是提示“进程在一个作业里” 用process explorer程序查看 ...
- Windows核心编程 第十一章 线程池的使用
第11章 线程池的使用 第8章讲述了如何使用让线程保持用户方式的机制来实现线程同步的方法.用户方式的同步机制的出色之处在于它的同步速度很快.如果关心线程的运行速度,那么应该了解一下用户方式的同步机制是 ...
- Windows核心编程 第七章 线程的调度、优先级和亲缘性(下)
7.6 运用结构环境 现在应该懂得环境结构在线程调度中所起的重要作用了.环境结构使得系统能够记住线程的状态,这样,当下次线程拥有可以运行的C P U时,它就能够找到它上次中断运行的地方. 知道这样低层 ...
- windows核心编程---第六章 线程的调度
每个线程都有一个CONTEXT结构,保存在线程内核对象中.大约每隔20ms windows就会查看所有当前存在的线程内核对象.并在可调度的线程内核对象中选择一个,将其保存在CONTEXT结构的值载入c ...
- 《windows核心编程》 17章 内存映射文件
内存映射文件主要用于以下三种情况: 系统使用内存映射文件载入并运行exe和dll,这大量节省了页交换文件的空间以及应用程序的启动时间 开发人员可以使用内存映射文件来访问磁盘上的数据文件.这使得我们可以 ...
- Windows核心编程 第十七章 -内存映射文件(下)
17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...
- Windows核心编程 第六章 线程基础知识 (上)
第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...
- windows核心编程---第七章 用户模式下的线程同步
用户模式下的线程同步 系统中的线程必须访问系统资源,如堆.串口.文件.窗口以及其他资源.如果一个线程独占了对某个资源的访问,其他线程就无法完成工作.我们也必须限制线程在任何时刻都能访问任何资源.比如在 ...
- 《Windows核心编程》第九章——用内核对象进行线程同步
先举一个有bug的例子: #include <iostream> #include <windows.h> #include <process.h> using n ...
随机推荐
- C语言初学者代码中的常见错误与瑕疵(13)
https://www.cpfn.org/bbs/viewtopic.php?f=85&t=5940&sid=ccbcf716d21191452e7c08a97b502337& ...
- viewpager viewpager+fragment
内页面 不单写页面 viewpager+布局 import java.util.ArrayList; import java.util.List; import android.os.Bundl ...
- Python标准库之核心模块学习记录
内建函数和异常 包括__builtin__模块和exceptions模块 操作系统接口模块 包括提供文件和进程处理功能的os模块,提供平台独立的文件名处理(分拆目录名,文件名,后缀等)的os.path ...
- linux内核中jiffies的回绕问题【转】
本文转载自:http://blog.csdn.net/yuanlulu/article/details/6019862 ======================================== ...
- Java中的TreeMap、Comparable、Comparator
我们知道HashMap的存储位置是按照key这个对象的hashCode来存放的,而TreeMap则是不是按照hashCode来存放,他是按照实现的Comparable接口的compareTo这个方法来 ...
- vlc分析
vlc的主界面对应的代码在vlc-2.2.1\modules\gui\qt4\main_interface.cpp.在相同目录下的qt4.cpp的module模块open函数里边new出实例: /* ...
- Javascript页面之间参数传递 (前端)
一.来源:tongfang [系统管理员] --[系统管理] 的"SysLeftNavView.ascx.cs 用户插件 usercontrol 左侧菜单导航: <li>< ...
- http://www.bejson.com/go.html?u=http://www.bejson.com/demo2.html
json 解析工具http://www.bejson.com/go.html?u=http://www.bejson.com/demo2.html
- sql 取时间 问题集
一. AND B.TRAFFICE_DATE>dateadd(day,5,(select getdate())) dateadd(day,5,(select getdate())):为当前时间+ ...
- php之属性重载和方法重载
<?php /** * * @authors Your Name (you@example.org) * @date 2016-06-13 20:40:19 * @version $Id$ */ ...