美文网首页
WriteFileEx异步IO

WriteFileEx异步IO

作者: Alliawell | 来源:发表于2022-02-18 07:49 被阅读0次

WriteFileEx function

SleepEx

1)异步写函数WriteFileEx()仅是发出写请求,然后就返回。该函数不使用LPOVERLAPPED中的HANDLE hEvent参数,用户可以在里面放一些自己的数据。

2)给每个WriteFileEx()准备一个POVERLAPPED对象,且buffer在IO完成前不能修改。

3)CompletionRoutine()和WriteFileEx()在同一个线程里被调用,通知用户I/O操作完成了。

写磁盘真正完成后,系统在调用WriteFileEx的线程里调用CompletionRoutine函数,因此线程需要用SleepEx或WaitSingleObject、WaitMultipleObjects来等待写磁盘完成。(可以发送多次写请求,然后再统一等待)。


WriteFileEx

异步写文件或I/O设备。该函数用异步的方式通知完成状态,调用指定的完成函数CompletionRoutine,且calling线程在alterable wait state。

原型

hFile

文件句柄,用CreateFile获取该句柄时必须用FILE_FLAG_OVERLAPPED 标记,和GENERIC_WRITE标记。

lpBuffer

缓冲区,包含需要写入到文件中的数据。

nNumberOfBytesToWrite

需要写入到文件中的数据量。

lpOverlapped

指向OVERLAPPED结构的指针,该数据在整个异步写操作中都会用到。因此该数据在写操作真正结束前,不能变的无效。

写文件时,用overlapped对象的Offset和OffsetHigh参数指定字节偏移量。

如果要在文件的最后面写数据,把Offset和OffsetHigh都设置成0xFFFF_FFFF即可。

该函数不使用OVERLAPPED的hEvent对象,用户可以留作自用。

WriteFileEx使用OVERLPPED的Internal和InernalHigh变量,用户不应该改变他们。

lpCompletionRoutine

指向一个回调函数,当写操作完成时会调用该函数。calling thread is in an alertable wait state.

返回值

函数成功则返回非零值。如果函数失败,则返回0,用GetLastError获取错误码。

如果WriteFileEx成功,calling thread有一个未完成的异步I/O操作:写数据到文件。当该I/O完成时,calling thread在alertable wait state,系统调用CompletionRoutine函数,且等待结束(等待码时WAIT_IO_COMPLETION).

如果函数成功且写文件操作完成,但是calling thread不在alertable wait state,系统会把completionRoutine的调用排入队列,直到the calling thread进入alertable wait state.

注意事项

当使用WriteFileEx时,即使返回成功也要调用GetLastError。例如当调用WriteFileEx时产生buffer溢出,函数会返回成功,但是GetLastError会用ERROR_MORE_DATA报告错误。

当有太多未完成的异步I/O请求时,WriteFileEx可能会返回错误,GetLastError会返回ERROR_INVALID_USER_BUFFER或ERROR_NOT_ENOUGH_MEMORY.

想要取消所有未完成的异步IO,使用:

CanelIo:仅取消该线程对file handle的操作;

CanelIoEx:取消所有线程对该file handle的操作。

取消的IO返回时有错误码ERROR_OPERATION_ABORTED.

在写操作完成前,不要修改buffer里的内容,否则可能会出错。

application使用WaitForSingleObjectExWaitForMultipleObjectsExMsgWaitForMultipleObjectsExSignalObjectAndWait, and SleepEx 函数来进入alertable wait state.

    #include <iostream>

#include<Windows.h>

#include<thread>

const int MAX_IO = 100000;

const int BUF_SIZE = 1024;

char bufArray[MAX_IO][BUF_SIZE];

OVERLAPPED gOverLap[MAX_IO];

int gCompletionNum = 0;

int gTotalBytesWritten = 0;

HANDLE gFileHandle;

//完成函数

void WINAPI CompletionRoutine(

    DWORD dwErrorCode,

    DWORD dwNumberOfBytesTransfered,

    LPOVERLAPPED lpOverlapped

) {

    gCompletionNum++;

    gTotalBytesWritten += dwNumberOfBytesTransfered;

    //打印错误码

    if (dwErrorCode != ERROR_SUCCESS) {

    printf("Error Code in CompletioRoutine is: %d\n.", dwErrorCode);

}

if (gCompletionNum == 1) {

auto threadId = std::this_thread::get_id();

printf("Thread Id of CompletionRoutine is :%d.\n", threadId);

}

return;

}

//线程函数,写磁盘

void ThreadFunc(void)

{

bool result = TRUE;

DWORD errCode = 0;

DWORD status = 0;

int wrCnt = 0;

auto threadId = std::this_thread::get_id();

printf("Thread Id of CompletionRoutine is :%d.\n", threadId);

for (int i = 0; i < MAX_IO; i++)

{

//异步写

result = WriteFileEx(gFileHandle,

bufArray[i],

BUF_SIZE,

&gOverLap[i],

CompletionRoutine);

//判断是否成功

if (FALSE == result)

{

errCode = GetLastError();

printf("Error Code at WriteFileEx is: %d.\n", errCode);

}

else {

wrCnt++;

}

}

//等待写磁盘结束

int i = 0;

while (gCompletionNum != wrCnt) {

status = SleepEx(INFINITE, TRUE);

i++;

printf("ThreadFunc = %d, SleepEx is called %d times.\n", gCompletionNum,i);

}

printf("gTotalBytesWritten is %d.\n", gTotalBytesWritten);

printf("WriteThread is finished.\n");

}

int main()

{

DWORD errCode = 0;

//初始化数组

for (int i = 0; i < MAX_IO; i++)

{

for (int j = 0; j < BUF_SIZE; j++)

{

bufArray[i][j] = i * BUF_SIZE + j;

}

}

//初始化overlapped

for (int i = 0; i < MAX_IO; i++) {

gOverLap[i].Offset = 0xFFFFFFFF;

gOverLap[i].OffsetHigh = 0xFFFFFFFF;

}

//打开文件

printf("Begin write thread...\n");

gFileHandle = CreateFile(L"E:\\Async.dat",

GENERIC_WRITE | GENERIC_READ,

FILE_SHARE_READ,

NULL,

CREATE_ALWAYS,

FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,

0);

if (INVALID_HANDLE_VALUE == gFileHandle) {

errCode = GetLastError();

printf("Failed to open file. ErrorCode = %d.\n", errCode);

getchar();

}

//写文件

std::thread t1(ThreadFunc);

//等待文件写完

t1.join();

//关闭文件

CloseHandle(gFileHandle);

getchar();

}

相关文章

  • WriteFileEx异步IO

    WriteFileEx function[https://docs.microsoft.com/en-us/win...

  • Java IO快速入门

    网络IO实现方式分为BIO(阻塞IO)、线程池伪异步IO、NIO(非阻塞IO)、AIO(异步非阻塞IO); 异步、...

  • 前端进阶全栈-Node的异步IO

    本文力图详尽解释node的异步IO: 异步IO的产生背景 Node中的异步IO具体的实现 非I/O的异步API 一...

  • Reactor 与Proactor

    按照posix标准,系统io分为同步io和异步io两种,其中同步io常用的是bio nio。异步io有aio。 从...

  • NodeJS基础原理

    NodeJS基础原理 异步IO原理浅析及优化方案 异步IO的好处(输入输出input output) 前端通过异步...

  • IO模型

    原文参考链接 四种状态 同步 异步 阻塞 非阻塞 IO分类 同步阻塞IO 同步非阻塞IO 异步非阻塞IO注意: 没...

  • 异步IO

    摘自廖雪峰教程 在IO编程一节中,我们已经知道,CPU的速度远远快于磁盘、网络等IO。在一个线程中,CPU执行代码...

  • 异步IO

    为什么要异步IO node的事件循环 在进程启动时,node会创建一个类似于while的循环,每执行一次循环体就是...

  • 阻塞非阻塞 同步异步 IO模型及其应用 NIO实现原理

    1.同步异步概念 2.阻塞非阻塞概念 3.常见I/O模型:同步阻塞IO,同步非阻塞IO,异步阻塞IO,异步非阻塞I...

  • nodejs深入学(5)异步编程

    前言 上一章讲解了node如何通过事件循环实现异步,包括与各种IO多路复用搭配实现的异步IO已经与IO无关的异步A...

网友评论

      本文标题:WriteFileEx异步IO

      本文链接:https://www.haomeiwen.com/subject/onvklrtx.html