异步设备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 ...
随机推荐
- php获取网页中图片并保存到本地
php获取网页中图片并保存到本地的代码,将网页中图片保存本地文件夹: save_img("http://www.jbxue.com" ?>
- android 项目学习随笔二十一(IM、语音识别、机器人、统计、扫描二维码、条形码)
语音识别:科大讯飞语音云 http://www.xfyun.cn/ 语音机器人模拟 public class TalkBean { public String text; public boolean ...
- scala多个构造函数的定义方法
直接上代码: package com.test.scalaw.test.demo /** * scala定义多个构造函数, * 另外,Scala中有只有一个主要构造函数,其他都是辅助构造函数.而且需要 ...
- TI CC254x BLE教程 2
连接更新请求(connection update request) 如果slave不满意现有的连接参数, 比如间隔, 延迟等等, 可以向master提出自己希望的参数范围 连接终止(connectio ...
- mysql+keepalived主从切换脚本 转
Keepalived MySQL故障自动切换脚本 MySQL架构为master-slave(主从),master故障自动切换到slave上.当然也可以设置为双master,但这里有个弊端:就是当主 ...
- git log用法【转】
转自:http://www.cnblogs.com/gbyukg/archive/2011/12/12/2285419.html PHP技术交流群 170855791 git log 查看提交记录,参 ...
- ORACLE 日期函数
ORACLE 日期函数 SYSDATE 当前的数据库系统时间 ADD_MONTHS(加减指定的月份) MONTHS_BETWEEN(取两个日期之间相隔的月数) LAST_DAY(取指定日期所在月的最 ...
- 怎么使用PHP获取用户客户端真实IP的解决方案呢?
function getIp(){if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIE ...
- jQuery_Ajax_Json 异步接收PHP端传来的json数据
[json]{"user_id":"1172940","rmb_point":"0","weixin_id&q ...
- HDU 3076:ssworld VS DDD(概率DP)
http://acm.split.hdu.edu.cn/showproblem.php?pid=3076 ssworld VS DDD Problem Description One day, s ...