异步设备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 ...
随机推荐
- 利用curl并发来提高页面访问速度
在我们平时的程序中难免出现同时访问几个接口的情况,平时我们用curl进行访问的时候,一般都是单个.顺序访问,假如有3个接口,每个接口耗时500毫 秒那么我们三个接口就要花费1500毫秒了,这个问题太头 ...
- SqlServer nvarchar中的中文字符匹配,更改SqlServer实例和数据库排序规则的办法
我们都知道在SqlServer中的nvarchar类型可以完美的存储诸如中文这种unicode字符,但是我们会发现有时候查询语句去查询nvarchar列的时候查不出来. 为什么nvarchar类型有时 ...
- where 子句和having子句中的区别
1.where 不能放在GROUP BY 后面 2.HAVING 是跟GROUP BY 连在一起用的,放在GROUP BY 后面,此时的作用相当于WHERE 3.WHERE 后面的条件中不能有聚集函数 ...
- IoC 依赖注入、以及在Spring中的实现
资源来自网络: 去年火得不行的Spring框架,一般的书籍都会从IoC和AOP开始介绍起,这个IoC概念,个人感觉资料里都写得让人看得有些痛苦,所谓IoC,就是控制反转(Inversion of Co ...
- listview中item 有checkbox多选防止滑动 listview页面 出现checkbox错位问题
checkbox点击切换背景 <CheckBox android:id="@+id/checkbox" android:layout_width="40dp&quo ...
- 将edit ctrL弄的像个dos
case WM_CTLCOLOREDIT: { HWND hShellText = GetDlgItem(hDlg,IDC_TXT_SHELL); if (hShellText == (HWND)lP ...
- mybatis n+1问题
mybatis的一对多或者多对多的时候,2中方式解决,一种是嵌套select,但是会有n+1问题,不推荐:另外一种是使用一条sql,在该sql里面使用子查询的方式来完成.比如 select * fro ...
- 测试驱动开发神器框架Mockito
作为菜鸟的我,以前没接触过Mock类型的框架,比如说要测试action层,我总是从action层调用service再调用dao访问数据库,这种方式从原则上来说是无疑是非常正确的,在没用mock框架之前 ...
- MySQL Replication的Reset slave重置命令
有时要清除从库的所有复制信息,如切换为不同的Master, 主从重做等:Reset slave是一个比较危险的命令,所以在执行前一定要准备知道其含义. 1. 命令在slave上执行,执行前一定要停掉s ...
- PHP开发异步高性能的MySQL代理服务器
ySQL数据库对每个客户端连接都会分配一个线程,所以连接非常宝贵.开发一个异步的MySQL代理服务器,PHP应用服务器可以长连接到这台Server,既减轻MYSQL的连接压力,又使PHP保持长连接减少 ...