您的位置:首页 > 编程语言

异步设备IO 《windows核心编程》第10章学习

2015-02-06 23:11 281 查看

异步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,0);
wcout<<L"FileSize:"<<dwFileSize<<endl;
char * pFileContent = new char[10000000];
DWORD dwReaded = 0;
OVERLAPPED o_Read = {0};
DWORD bReadDone = ::ReadFile(hFile,
pFileContent,
10000000,
&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,0);
wcout<<L"FileSize:"<<dwFileSize<<endl;
LARGE_INTEGER liDis = {0};
LARGE_INTEGER liRet = {0};
::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
char * pFileContent = new char[10000000];
memset(pFileContent,'z',10000000);
DWORD dwReaded = 0;
OVERLAPPED o_Write = {0};
o_Write.Offset = liRet.LowPart;
o_Write.hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
DWORD bReadDone = ::WriteFile(hFile,
pFileContent,
10000000,
&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,0);
wcout<<L"FileSize:"<<dwFileSize<<endl;
LARGE_INTEGER liDis = {0};
LARGE_INTEGER liRet = {0};
::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
char * pFileContent = new char[10000000];
memset(pFileContent,'g',10000000);
DWORD dwReaded = 0;
OVERLAPPED o_Write = {0};
o_Write.Offset = liRet.LowPart;
DWORD bReadDone = ::WriteFileEx(hFile,
pFileContent,
10000000,
&o_Write,
FileIOCompletionRoutine);

::CloseHandle(hFile);
SleepEx(10000,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 0;
}
else if(dw == WAIT_IO_COMPLETION)
{
wcout<<L"QueueUserApc Forced us out of a wait state"<<endl;
return 0;
}
return 0;
}
void Test4()
{
//利用QueueUserApc来停止线程等待
HANDLE hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE hThread = (HANDLE) _beginthreadex(NULL,0,ThreadFunc,hEvent,0,NULL);
Sleep(5000);
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,0,NULL,CREATE_NEW,FILE_FLAG_OVERLAPPED,NULL);

//创建完成端口
HANDLE hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,4);
if(hIOCP==NULL)
{
printf("完成端口创建失败!");
}

//绑定完成端口
CreateIoCompletionPort(hSrcFile,hIOCP,READ_KEY,0);
CreateIoCompletionPort(hDstFile,hIOCP,WRITE_KEY,0);

OVERLAPPED ov={0};
PostQueuedCompletionStatus(hIOCP,0,WRITE_KEY,&ov);
OVERLAPPED ovSrc={0};
OVERLAPPED ovDes={0};
ULONG_PTR CompletionKey;
BYTE* pBuffer=new BYTE[BUFFERSIZE];
int i=0;
int j=0;
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,0,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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: