IOCP
IOCP是唯一一个不需要安全属性的Windows内核对象。 这是因为IO完成端口在设计时就是只在一个进程中使用。
原理
通常的办法是,线程池中的工作线程的数量与CPU内核数量相同,以此来最小化线程切换代价。一个IOCP对象,在操作系统中可关联着多个Socket和(或)文件控制端。 IOCP对象内部有一个先进先出(FIFO)队列,用于存放IOCP所关联的输入输出端的服务请求完成消息。请求输入输出服务的进程不接收IO服务完成通知,而是检查IOCP的消息队列以确定IO请求的状态。 (线程池中的)多个线程负责从IOCP消息队列中取走完成通知并执行数据处理;如果队列中没有消息,那么线程阻塞挂起在该队列。这些现成从而实现了负载均衡。
引自维基百科
IOCP是Windows提供给我们的一整套的东西(工具库)
1.创建一个队列(一个完成端口会创建一个)
包含了设备
可以有多个设备对应一个完成端口
2.设备操作的队列
对我设备进行挨个的操作
3.线程池
多个线程
创建一个完成端口
使用CreateIoCompletionPort
原型
HANDLE WINAPI CreateIoCompletionPort(
_In_ HANDLE FileHandle, // 设备内核对象
_In_opt_ HANDLE ExistingCompletionPort, // 已存在的完成端口
_In_ ULONG_PTR CompletionKey, // 完成端口的一个Key值,我们可以通过define进行一个设置
_In_ DWORD NumberOfConcurrentThreads // 创建多少个线程,默认值为0, 表示一个核心对应一个线程, 也就是说, 8核心就是8线程, 4核心就是4线程,不建议设置为100个这样的数量,线程切换会消耗资源
);如果是8核,实际的物理线程就是8个,可以设置为100个线程,但是它只是做了一个线程模拟,因为它真正只能做到8个线程
两种创建方式:
1.先创建一个端口,再打开文件,再进行端口与设备的绑定
//创建一个端口
HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
//打开一个文件
HANDLE hFile = CreateFile(TEXT("Demo.txt"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_FLAG_OVERLAPPED,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
// 绑定设备和端口
CreateIoCompletionPort(hFile,
hIOCP, //指定端口
IOCP_KEY_READ,
0);
OVERLAPPED oRead = {0};
oRead.Offset = 0;
DWORD dwNumberOfBytesTransferred = 100;
}
else
{
// GetLastError()
}2.创建一个与指定文件绑定的端口
HANDLE hIOCP = CreateIoCompletionPort( hFile,
NULL,
IOCP_KEY_READ,
0);同样也是要拿到文件句柄,只是少了一个创建自由端口的步骤,直接与文件进行绑定了而已
插入一个请求
PostQueuedCompletionStatus
原型
BOOL WINAPI PostQueuedCompletionStatus(
_In_ HANDLE CompletionPort, // 完成端口
_In_ DWORD dwNumberOfBytesTransferred, // 传输的数据长度, 用于GetQueuedCompletionStatus获取的时候
_In_ ULONG_PTR dwCompletionKey, // IO完成端口的KEY
_In_opt_ LPOVERLAPPED lpOverlapped // OVERLAPPED结构体指针
);
从指定的IO完成端口取数据
GetQueuedCompletionStatus
原型:
BOOL WINAPI GetQueuedCompletionStatus(
_In_ HANDLE CompletionPort, // IO完成端口
_Out_ LPDWORD lpNumberOfBytes, // 取出的数据数的指针
_Out_ PULONG_PTR lpCompletionKey, // IO完成端口的KEY
_Out_ LPOVERLAPPED *lpOverlapped, // 指向OVERLAPPED结构体指针的指针
_In_ DWORD dwMilliseconds // 等待的毫秒数
);注意:
如果没有完成数据包队列, 该功能将等待与完成端口关联的待处理的IO操作完成.
如果在指定时间内没有出现完成数据包, 则函数超时, 返回FALSE, 并将 *lpOverlapped 设置为NULL
如果dwMilliseconds是INFINITE, 则该函数永远不会超时
如果dwMilliseconds为零, 并且没有IO操作出现, 则该函数将立即超时.