WriteFileEx异步IO

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使用WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx, SignalObjectAndWait, and SleepEx 函数来进入alertable wait state.

    #include

#include

#include

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)