Windows服务器端编程-第二章 设备IO与线程间通信-6-创建完成端口
2007-07-31 11:20
281 查看
l 创建完成端口
完成端口的原理是并发运行的线程必须有一个上限;也就是500个并行的客户端不允许500个线程同时存在。那么,仅仅是确切的并发运行的线程数目么?是的,如果仔细想想,就会意识到如果在一个双CPU的机器上有多于两个可运行的线程,而每个CPU对应于一个线程,并没有多大意义。一旦线程数量超过可用的CPU数量,系统就不得不花费时间进行线程切换,这将浪费CPU周期,这是并行模型的低效之处。
并行模型的另一个低效之处是为每个客户端请求创建新线程。相对于在本身的虚地址空间创建新进程来说,创建线程代价较低,但并不是免费的。如果在服务应用程序初始化的时候建立线程池将会提高性能,这些线程可以在程序内循环使用。I/O完成端口被设计成使用线程池来工作。
I/O完成端口可能是最复杂的内核对象。要创建I/O完成端口,需要调用CreateIoCompletionPort函数:
HANDLE CreateIoCompletionPort(
HANDLE hfile,
HANDLE hExistingCompPort,
ULONG_PTR CompKey,
DWORD dwNumberOfConcurrentThreads);
该函数执行两个不同的任务:创建I/O完成端口,将设备与I/O完成端口关联。这个函数相当复杂,在我看来,微软应该将其拆分为两个函数。当我使用I/O完成端口时,创建两个小函数来将CreateIoCompletionPort的两种能力分开。我创建第一个函数称为CreateNewCompletionPort,实现如下:
HANDLE CreateNewCompletionPort(DWORD dwNumberOfConcurrentThreads) {
return(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
dwNumberOfConcurrentThreads));
}
该函数带有一个参数:dwNumberOfConcurrentThreads,内部调用CreateIoCompletionPort函数,将硬编码的值作为前三个参数,dwNumberOfCocurrentThreads作为最后一个。可以看到,CreateIoCompletionPort函数的前三个参数仅在将设备与完成端口关联时有用(很快会讲到)。为了创建完成端口,我将用INVALID_HANDLE_VALUE,NULL,0来对应CreateIoCompletionPort的前三个参数。
dwNumberOfConcurrentThreads参数告诉完成端口同时可运行线程的最大数量。如果该参数为0,完成端口默认与值与机器的CPU数相同。这对于避免额外的线程切换相当有用。如果客户端请求需要较长的运算,增加这个值会减少阻塞,但强烈建议不要增加这个值。可以尝试不同的值来体验一下应用程序的表现。
完成端口的原理是并发运行的线程必须有一个上限;也就是500个并行的客户端不允许500个线程同时存在。那么,仅仅是确切的并发运行的线程数目么?是的,如果仔细想想,就会意识到如果在一个双CPU的机器上有多于两个可运行的线程,而每个CPU对应于一个线程,并没有多大意义。一旦线程数量超过可用的CPU数量,系统就不得不花费时间进行线程切换,这将浪费CPU周期,这是并行模型的低效之处。
并行模型的另一个低效之处是为每个客户端请求创建新线程。相对于在本身的虚地址空间创建新进程来说,创建线程代价较低,但并不是免费的。如果在服务应用程序初始化的时候建立线程池将会提高性能,这些线程可以在程序内循环使用。I/O完成端口被设计成使用线程池来工作。
I/O完成端口可能是最复杂的内核对象。要创建I/O完成端口,需要调用CreateIoCompletionPort函数:
HANDLE CreateIoCompletionPort(
HANDLE hfile,
HANDLE hExistingCompPort,
ULONG_PTR CompKey,
DWORD dwNumberOfConcurrentThreads);
该函数执行两个不同的任务:创建I/O完成端口,将设备与I/O完成端口关联。这个函数相当复杂,在我看来,微软应该将其拆分为两个函数。当我使用I/O完成端口时,创建两个小函数来将CreateIoCompletionPort的两种能力分开。我创建第一个函数称为CreateNewCompletionPort,实现如下:
HANDLE CreateNewCompletionPort(DWORD dwNumberOfConcurrentThreads) {
return(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
dwNumberOfConcurrentThreads));
}
该函数带有一个参数:dwNumberOfConcurrentThreads,内部调用CreateIoCompletionPort函数,将硬编码的值作为前三个参数,dwNumberOfCocurrentThreads作为最后一个。可以看到,CreateIoCompletionPort函数的前三个参数仅在将设备与完成端口关联时有用(很快会讲到)。为了创建完成端口,我将用INVALID_HANDLE_VALUE,NULL,0来对应CreateIoCompletionPort的前三个参数。
dwNumberOfConcurrentThreads参数告诉完成端口同时可运行线程的最大数量。如果该参数为0,完成端口默认与值与机器的CPU数相同。这对于避免额外的线程切换相当有用。如果客户端请求需要较长的运算,增加这个值会减少阻塞,但强烈建议不要增加这个值。可以尝试不同的值来体验一下应用程序的表现。
相关文章推荐
- Windows服务器端编程-第二章 设备IO与线程间通信-8-围绕I/O完成端口的架构
- Windows服务器端编程-第二章 设备IO与线程间通信-9-I/O完成端口对线程池的管理
- Windows服务器端编程-第二章 设备IO与线程通信-5-I/O完成端口
- Windows服务器端编程-第二章 设备IO与线程间通信-7-将设备与完成端口关联
- Windows服务器端编程-第二章 设备IO与线程间通信-2-异步设备I/O操作基础
- Windows服务器端编程-第二章 设备IO和线程间通信-3-接收I/O请求的完成通知
- Windows服务器端编程-第二章 设备IO与线程间通信-10-线程池有多少线程
- Windows服务器端编程-第二章 设备IO与线程间通信-11-模拟已完成的I/O请求
- Windows服务器端编程-第二章 设备IO和线程间通信-4-警告式I/O的优缺点
- Windows服务器端编程-第二章 设备I/O与线程间通信-1
- Windows服务器端编程-第二章 设备IO与线程间通信-12-代码清单(完)
- 卷二 Dalvik与Android源码分析 第二章 进程与线程 2.2 Dalvik线程创建机制 图书版试读--请勿转发
- 黑马程序员_多线程技术(线程的创建Thread和Runnble,死锁,线程间通信,join,yield)
- Qt QThread 线程创建,线程同步,线程通信 实例
- 线程间的通信,避免创建过多线程
- RT-Thread 学习笔记(二)---线程创建及任务间通信之中断锁
- java多线程学习之创建线程与线程间通信
- 黑马程序员--读写字节数组,随机读写流,集合IO的思维导图,多线程部分,单例设计模式,线程和进程的概念,Java中的线程的创建方式,线程的随机性,线程的状态图,多线程操作共享数据的安全性,死锁
- ios线程-创建及通信
- C# 线程手册 第二章 .NET 中的线程 创建一个线程