异步设备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 ...
随机推荐
- PTPX中的time_based analysis
根据VCD文件的type,PTPX支持instantaneous peak power analysis和cycle_accurate peak power analysis. Time-Based ...
- PAT乙级 1019. 数字黑洞 (20)
1019. 数字黑洞 (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 给定任一个各位数字不完全相同的4位 ...
- RobotFramework 安装配置(二)
前面已经写了一篇关于RF的安装配置了,那是在做自动化工具调研的时候搭建RF总结的,基于win32的系列软件安装的过程.经过1个月的调研,做成了demo,也大致学RF的使用和python的基础语法,暂时 ...
- 创建DirectInput接口对象说明---(void **)&m_pDI
读别人代码时遇到的,起初没明白过来这是怎么回事,后来忽然想明白了. if (FAILED(DirectInput8Create(appInstance, DIRECTINPUT_VERSION, II ...
- Java 的局部变量和成员变量
在Java语言中没有全局变量 分析各种变量的作用域的最简单方法是以花括号为界, 1.在类体中定义的是成员变量,成员变量会被默认初始化 2.在方法中定义的是局部变量,局部变量不会被默认初始化
- Qt可执行程序写入版本信息
[1]新建Qt工程 1.1 具体新建步骤不赘述. 1.2 新建工程后文件目录如下: 1.3 留意对比一下你的代码目录,可以发现我的文件目录中多了一个rc类型的资源文件.那么,它也就是关键点. 1.4 ...
- 网上书城分类Category模块
2 分类模块 2.1 创建分类模块相关类 在每个模块开始时,都要创建如下基本类:实体类.DAO类.Service类.Servlet类: l cn.itcast.goods.category.domai ...
- 160913、ionic + 高德地图定位
实例一: var AMapArea=document.getElementById('amap'); AMapArea.parentNode.style.height="100%" ...
- Java Properties工具类详解
1.Java Properties工具类位于java.util.Properties,该工具类的使用极其简单方便.首先该类是继承自 Hashtable<Object,Object> 这就奠 ...
- 文本框textarea实时提示还可以输入多少文字
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content=&q ...