异步I/O 设备内核对象,事件内核对象,可提醒I/O 接收I/O通知

本文详细介绍了Windows环境下异步I/O操作的基本概念,包括CreateFile、SetFilePointerEx、SetEndOfFile、FlushFileBuffers及FILE_FLAG_WRITE_THROUGH功能的应用。此外,文章还阐述了如何通过CancelIo、CancelIoEx取消I/O请求,并讨论了SleepEx等函数如何影响线程的可提醒状态。进一步地,通过DeviceObject、TrrigEvent和AlertableIO函数展示了异步过程调用(APC)队列的使用场景与实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CreateFile

SetFilePointerEx
SetEndOfFile
FlushFileBuffers 类似FILE_FLAG_WRITE_THROUGH功能

在异步I/O请求完成之前,一定不能移动或是销毁在发出I/O请求时所使用的数据缓存和OVERLAPPED结构。

BOOL WINAPI CancelIo(
  __in  HANDLE hFile
);
取消同给定句柄所标识的线程添加到队列中的所有I/O请求(除非该句柄具有与之相关联的I/O完成端口)
BOOL WINAPI CancelIoEx(
  __in      HANDLE hFile,
  __in_opt  LPOVERLAPPED lpOverlapped
);
取消指定I/O请求,如lpOverlapped为NULL,取消所有

可置线程为可提醒状态的函数:
SleepEx/WaitForSingleObjectEx/WaitForMultipleObjectsEx/SignalObjectAndWait/GetQueuedCompletionStatusEx/MsgWaitForMultipleObjectsEx
bAlertable 为TRUE, 不带Ex的函数实际是调用Ex并传入FLASE。

调用这6个函数,系统会先检查APC队列有没有项,如有,系统不会让线程进入睡眠状态。没有时才会挂起
当系统创建一个线程的时候,会同时创建一个与线程相关联的队列,这个队列被称为异步过程调用APC

DWORD WINAPI QueueUserAPC(
  __in  PAPCFUNC pfnAPC,
  __in  HANDLE hThread,
  __in  ULONG_PTR dwData
);
手动加入一项到APC队列

用来接收I/O完成通知的方法
1.触发设备内核对象
2.触发事件内核对象
3.使用可提醒I/O
4.使用I/O完成端口

#include <Windows.h>
#include <stdio.h>
#include <process.h>

void DeviceObject()
{
	//FILE_FLAG_WRITE_THROUGH Instructs the system to write through any intermediate cache and go directly to disk. The system can still cache write operations, but cannot lazily flush them. 
	//FILE_FLAG_DELETE_ON_CLOSE CloseHandle will delete this temp file.
	HANDLE hFile = CreateFileW(L"c:\\test\\temp.txt",GENERIC_READ|GENERIC_WRITE|FILE_SHARE_DELETE,0,NULL,
		CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE|FILE_FLAG_OVERLAPPED,NULL);
	wchar_t buf[11] = L"1234567890";
	OVERLAPPED ov = { 0 };
	ov.Offset = 3;
	BOOL bWriteDoned = WriteFile(hFile,buf,8*sizeof(wchar_t),NULL,&ov);
	DWORD dw = GetLastError();

	if( !bWriteDoned && (dw == ERROR_IO_PENDING) )
	{
		wprintf(L"dw == ERROR_IO_PENDING.\n");
		WaitForSingleObject(hFile, INFINITE);

		bWriteDoned = TRUE;
	}

	if(bWriteDoned)
	{
		wprintf(L"write over.\n");
	}
	else
	{
		wprintf(L"other fail.\n");
	}
}

void TrrigEvent()
{
	HANDLE hFile = CreateFileW(L"c:\\test\\temp.txt",GENERIC_READ|GENERIC_WRITE|FILE_SHARE_DELETE,0,NULL,
		CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY/*|FILE_FLAG_DELETE_ON_CLOSE*/|FILE_FLAG_OVERLAPPED,NULL);

	wchar_t buf[11] = L"1234567890";
	OVERLAPPED ovWrite = { 0 };
	ovWrite.Offset = 3;
	ovWrite.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	BOOL bWriteDoned = WriteFile(hFile,buf,8*sizeof(wchar_t),NULL,&ovWrite);

	BYTE bufRead[20];
	OVERLAPPED ovRead = { 0 };
	ovRead.Offset = 6;
	ovRead.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	ReadFile(hFile,bufRead,20,NULL,&ovRead);
	
	HANDLE hEvent[2] = { ovWrite.hEvent, ovRead.hEvent };
	bool bWrite = true, bRead = true;
	do
	{
		DWORD dw = WaitForMultipleObjects(2,hEvent,FALSE,INFINITE);
		switch( dw - WAIT_OBJECT_0 )
		{
		case 0:
		{
			wprintf(L"Write completed.\n");
			bWrite = false;
			break;
		}
		case 1:
		{
			wprintf(L"Read completed.\n");
			bRead = false;
			break;
		}
		}
	}
	while(bWrite | bRead);
}

VOID WINAPI APCFunc(ULONG_PTR dwParam)
{
	dwParam;
}
unsigned __stdcall ThreadFunc( void* pArguments )
{
    HANDLE hEvent = (HANDLE)pArguments;
	//Waits until (1)the specified object is in the signaled state, 
	//			  (2)an I/O completion routine or asynchronous procedure call (APC) is queued to the thread, 
	//			  (3)or the time-out interval elapses.
	DWORD dw = WaitForSingleObjectEx(hEvent,5000,TRUE);
	switch( dw )
	{
	case WAIT_OBJECT_0:
	{
		wprintf(L"Event is signaled.\n");
		break;
	}
	case WAIT_IO_COMPLETION:
	{
		wprintf(L"IO completed.\n");
		break;
	}
	case WAIT_TIMEOUT:
	{
		wprintf(L"timeout.\n");
		break;
	}
	}
    _endthreadex( 0 );
    return 0;
} 

void AlertableIO()
{
	HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadFunc, hEvent, 0, NULL );
	//; //(1)will timeout
	Sleep(1);	//make sure thread function have run to WaitForSingleObjectEx function.
	QueueUserAPC(APCFunc,hThread,NULL); //(2)will IO completed
	//SetEvent(hEvent); // (3)will signaled

	WaitForSingleObject( hThread, INFINITE );
	CloseHandle(hThread);
	CloseHandle(hEvent);
}


void main()
{
	//DeviceObject();
	//getchar();

	//TrrigEvent();
	//getchar();

	AlertableIO();
	getchar();
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值