[C#]I/O完成端口的类定义和测试实例

简介:
整理者:郑昀@UltraPower 
日期:2005-04-13 

从William Kennedy那里整理过来的,不同之处在于他自己定义了一个Overlapped,而我们这里直接使用 
System.Threading.NativeOverlapped:。 

附一段我以前的Win32下的IOCP文档,如果您了解IOCP也可以直接跳过看后面的C#测试示范: 

我们采用的是I/O Complete Port(以下简称IOCP)处理机制。

简单的讲,当服务应用程序初始化时,它应该先创建一个I/O CP。我们在请求到来后,将得到的数据打包用PostQueuedCompletionStatus发送到IOCP中。这时需要创建一些个线程(7个线程/CPU,再多就没有意义了)来处理发送到IOCP端口的消息。实现步骤大致如下:

1     先在主线程中调用CreateIoCompletionPort创建IOCP

CreateIoCompletionPort的前三个参数只在把设备同Complete Port相关联时才有用。

此时我们只需传递INVALID_HANDLE_VALUE,NULL0即可。

第四个参数告诉端口同时能运行的最多线程数,这里设置为0,表示默认为当前计算机的CPU数目。

2     我们的ThreadFun线程函数执行一些初始化之后,将进入一个循环,该循环会在服务进程终止时才结束。

在循环中,调用GetQueuedCompletionStatus,这样就把当前线程的ID放入一个等待线程队列中,I/O CP内核对象就总能知道哪个线程在等待处理完成的I/O请求。

如果在IDLE_THREAD_TIMEOUT规定的时间内I/O CP上还没有出现一个Completion Packet,则转入下一次循环。在这里我们设置的IDLE_THREAD_TIMEOUT1秒。

 

当端口的I/O完成队列中出现一项时,完成端口就唤醒等待线程队列中的这个线程,该线程将得到完成的I/O项中的信息:       传输的字节数、完成键和OVERLAPPED结构的地址。

 

在我们的程序中可以用智能指针或者BSTR或者int来接受这个OVERLAPPED结构的地址的值,从而得到消息;然后在这个线程中处理消息。

GetQueuedCompletionStatus的第一个参数hCompletionPort指出了要监视哪一个端口,这里我们传送先前从CreateIoCompletionPort返回的端口句柄。

 

需要注意的是:

第一,   线程池的数目是有限制的,和CPU数目有关系。

第二,   IOCP是一种较为完美的睡眠/唤醒 线程机制;线程当前没有任务要处理时,就进入睡眠状态,从而不占用CPU资源,直到被内核唤醒;

第三,   最近一次刚执行完的线程,下次任务来的时候还会唤醒它;所以有可能比较少被调用的线程以后被调用的几率也少。

 


测试代码: 
 
using  System; 
using  System.Threading;   //  Included for the Thread.Sleep call  
using  Continuum.Threading; 
using  System.Runtime.InteropServices; 
 
namespace  IOCPDemo 

    
//=============================================================================
    /// <summary> Sample class for the threading class </summary> 
    public class UtilThreadingSample 
    

        
//*****************************************************************************    
        /// <summary> Test Method </summary> 
        static void Main() 
        

            
// Create the MSSQL IOCP Thread Pool 
            IOCPThreadPool pThreadPool = new IOCPThreadPool(01020new IOCPThreadPool.USER_FUNCTION(IOCPThreadFunction)); 
       
            
//for(int i =1;i<10000;i++) 
            
                pThreadPool.PostEvent(
1234); 
            }
 
       
            Thread.Sleep(
100); 
       
            pThreadPool.Dispose(); 
        }
 
     
        
//******************************************************************** 
        /// <summary> Function to be called by the IOCP thread pool.  Called when 
        
///           a command is posted for processing by the SocketManager </summary> 
        
/// <param name="iValue"> The value provided by the thread posting the event </param>
 
        static public void IOCPThreadFunction(int iValue) 
        

            
try 
            

                Console.WriteLine(
"Value: {0}", iValue.ToString()); 
                Thread.Sleep(
3000); 
            }
 
       
            
catch (Exception pException) 
            

                Console.WriteLine(pException.Message); 
            }
 
        }
 
    }
 
 
}
 


类代码: 
using  System; 
using  System.Threading; 
using  System.Runtime.InteropServices; 
 
namespace  IOCPThreading 

    [StructLayout(LayoutKind.Sequential, CharSet
=CharSet.Auto)] 
 
    
public sealed class IOCPThreadPool 
    

        [DllImport(
"Kernel32", CharSet=CharSet.Auto)] 
        
private unsafe static extern UInt32 CreateIoCompletionPort(UInt32 hFile, UInt32 hExistingCompletionPort, UInt32* puiCompletionKey, UInt32 uiNumberOfConcurrentThreads); 
 
        [DllImport(
"Kernel32", CharSet=CharSet.Auto)] 
        
private unsafe static extern Boolean CloseHandle(UInt32 hObject); 
 
        [DllImport(
"Kernel32", CharSet=CharSet.Auto)] 
        
private unsafe static extern Boolean PostQueuedCompletionStatus(UInt32 hCompletionPort, UInt32 uiSizeOfArgument, UInt32* puiUserArg, System.Threading.NativeOverlapped* pOverlapped); 
 
        [DllImport(
"Kernel32", CharSet=CharSet.Auto)] 
        
private unsafe static extern Boolean GetQueuedCompletionStatus(UInt32 hCompletionPort, UInt32* pSizeOfArgument, UInt32* puiUserArg, System.Threading.NativeOverlapped** ppOverlapped, UInt32 uiMilliseconds); 
 
        
private const UInt32 INVALID_HANDLE_VALUE = 0xffffffff
        
private const UInt32 INIFINITE = 0xffffffff
        
private const Int32 SHUTDOWN_IOCPTHREAD = 0x7fffffff
        
public delegate void USER_FUNCTION(int iValue); 
        
private UInt32 m_hHandle; 
        
private UInt32 GetHandle get return m_hHandle; } set { m_hHandle = value; } } 
 
        
private Int32 m_uiMaxConcurrency; 
 
        
private Int32 GetMaxConcurrency get return m_uiMaxConcurrency; } set { m_uiMaxConcurrency = value; } } 
 
 
        
private Int32 m_iMinThreadsInPool; 
 
        
private Int32 GetMinThreadsInPool get return m_iMinThreadsInPool; } set { m_iMinThreadsInPool = value; } } 
 
        
private Int32 m_iMaxThreadsInPool; 
 
        
private Int32 GetMaxThreadsInPool get return m_iMaxThreadsInPool; } set { m_iMaxThreadsInPool = value; } } 
 
 
        
private Object m_pCriticalSection; 
 
        
private Object GetCriticalSection get return m_pCriticalSection; } set { m_pCriticalSection = value; } } 
 
 
        
private USER_FUNCTION m_pfnUserFunction; 
 
        
private USER_FUNCTION GetUserFunction get return m_pfnUserFunction; } set { m_pfnUserFunction = value; } } 
 
 
        
private Boolean m_bDisposeFlag; 
 
        
/// <summary> SimType: Flag to indicate if the class is disposing </summary> 
 
        
private Boolean IsDisposed get return m_bDisposeFlag; } set { m_bDisposeFlag = value; } } 
 
        
private Int32 m_iCurThreadsInPool; 
 
        
/// <summary> SimType: The current number of threads in the thread pool </summary> 
 
        
public Int32 GetCurThreadsInPool get return m_iCurThreadsInPool; } set { m_iCurThreadsInPool = value; } } 
 
        
/// <summary> SimType: Increment current number of threads in the thread pool </summary> 
 
        
private Int32 IncCurThreadsInPool() return Interlocked.Increment(ref m_iCurThreadsInPool); } 
 
        
/// <summary> SimType: Decrement current number of threads in the thread pool </summary> 
 
        
private Int32 DecCurThreadsInPool() return Interlocked.Decrement(ref m_iCurThreadsInPool); } 
 
 
        
private Int32 m_iActThreadsInPool; 
 
        
/// <summary> SimType: The current number of active threads in the thread pool </summary> 
 
        
public Int32 GetActThreadsInPool get return m_iActThreadsInPool; } set { m_iActThreadsInPool = value; } } 
 
        
/// <summary> SimType: Increment current number of active threads in the thread pool </summary> 
 
        
private Int32 IncActThreadsInPool() return Interlocked.Increment(ref m_iActThreadsInPool); } 
 
        
/// <summary> SimType: Decrement current number of active threads in the thread pool </summary> 
 
        
private Int32 DecActThreadsInPool() return Interlocked.Decrement(ref m_iActThreadsInPool); } 
 
 
        
private Int32 m_iCurWorkInPool; 
 
        
/// <summary> SimType: The current number of Work posted in the thread pool </summary> 
 
        
public Int32 GetCurWorkInPool get return m_iCurWorkInPool; } set { m_iCurWorkInPool = value; } } 
 
        
/// <summary> SimType: Increment current number of Work posted in the thread pool </summary> 
 
        
private Int32 IncCurWorkInPool() return Interlocked.Increment(ref m_iCurWorkInPool); } 
 
        
/// <summary> SimType: Decrement current number of Work posted in the thread pool </summary> 
 
        
private Int32 DecCurWorkInPool() return Interlocked.Decrement(ref m_iCurWorkInPool); } 
 
        
public IOCPThreadPool(Int32 iMaxConcurrency, Int32 iMinThreadsInPool, Int32 iMaxThreadsInPool, USER_FUNCTION pfnUserFunction) 
        

            
try 
            

                
// Set initial class state 
 
                GetMaxConcurrency   
= iMaxConcurrency; 
 
                GetMinThreadsInPool 
= iMinThreadsInPool; 
 
                GetMaxThreadsInPool 
= iMaxThreadsInPool; 
 
                GetUserFunction     
= pfnUserFunction; 
 
 
                
// Init the thread counters 
 
                GetCurThreadsInPool 
= 0
 
                GetActThreadsInPool 
= 0
 
                GetCurWorkInPool    
= 0
 
 
                
// Initialize the Monitor Object 
 
                GetCriticalSection 
= new Object(); 
 
 
                
// Set the disposing flag to false 
 
                IsDisposed 
= false
 
 
                
unsafe 
                

 
                    
// Create an IO Completion Port for Thread Pool use 
                    GetHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0null, (UInt32) GetMaxConcurrency); 
 
                }
 
 
 
                
// Test to make sure the IO Completion Port was created 
 
                
if (GetHandle == 0
 
                    
throw new Exception("Unable To Create IO Completion Port"); 
 
 
                
// Allocate and start the Minimum number of threads specified 
 
                Int32 iStartingCount 
= GetCurThreadsInPool; 
 
         
 
                ThreadStart tsThread 
= new ThreadStart(IOCPFunction); 
 
                
for (Int32 iThread = 0; iThread < GetMinThreadsInPool; ++iThread) 
                

 
                    
// Create a thread and start it 
 
                    Thread thThread 
= new Thread(tsThread); 
 
                    thThread.Name 
= "IOCP " + thThread.GetHashCode(); 
 
                    thThread.Start(); 
 
 
                    
// Increment the thread pool count 
 
                    IncCurThreadsInPool(); 
 
                }
 
 
            }
 
 
 
            
catch 
            

 
                
throw new Exception("Unhandled Exception"); 
 
            }
 
 
        }
 
 
        
~IOCPThreadPool() 
        

 
            
if (!IsDisposed) 
 
                Dispose(); 
 
        }
 
 
        
public void Dispose() 
        

 
            
try 
            

 
                
// Flag that we are disposing this object 
 
                IsDisposed 
= true
 
 
                
// Get the current number of threads in the pool 
 
                Int32 iCurThreadsInPool 
= GetCurThreadsInPool; 
 
 
                
// Shutdown all thread in the pool 
 
                
for (Int32 iThread = 0; iThread < iCurThreadsInPool; ++iThread) 
                

                    
unsafe 
                    

 
                        
bool bret = PostQueuedCompletionStatus(GetHandle, 4, (UInt32*) SHUTDOWN_IOCPTHREAD, null); 
 
                    }
 
 
                }
 
 
 
                
// Wait here until all the threads are gone 
 
                
while (GetCurThreadsInPool != 0) Thread.Sleep(100); 
 
 
                
unsafe 
                

 
                    
// Close the IOCP Handle 
                    CloseHandle(GetHandle); 
 
                }
 
 
            }
 
 
            
catch 
            

 
            }
 
 
        }
 
        
private void IOCPFunction() 
        

            UInt32 uiNumberOfBytes; 
 
            Int32  iValue; 
 
            
try 
            

                
while (true
                

 
                    
unsafe 
                    

 
                        System.Threading.NativeOverlapped
* pOv; 
 
 
                        
// Wait for an event 
 
                        GetQueuedCompletionStatus(GetHandle, 
&uiNumberOfBytes, (UInt32*&iValue, &pOv, INIFINITE); 
                    }
 
 
                    
// Decrement the number of events in queue 
 
                    DecCurWorkInPool(); 
 
 
                    
// Was this thread told to shutdown 
 
                    
if (iValue == SHUTDOWN_IOCPTHREAD) 
 
                        
break
 
 
                    
// Increment the number of active threads 
 
                    IncActThreadsInPool(); 
 
 
                    
try 
                    

                        
// Call the user function 
                        GetUserFunction(iValue); 
 
                    }
 
 
                    
catch(Exception ex) 
                    

                        
throw ex; 
                    }
 
 
 
                    
// Get a lock 
 
                    Monitor.Enter(GetCriticalSection); 
 
 
                    
try 
                    

 
                        
// If we have less than max threads currently in the pool 
 
                        
if (GetCurThreadsInPool < GetMaxThreadsInPool) 
                        

 
                            
// Should we add a new thread to the pool 
 
                            
if (GetActThreadsInPool == GetCurThreadsInPool) 
                            

 
                                
if (IsDisposed == false
                                

 
                                    
// Create a thread and start it 
 
                                    ThreadStart tsThread 
= new ThreadStart(IOCPFunction); 
 
                                    Thread thThread 
= new Thread(tsThread); 
 
                                    thThread.Name 
= "IOCP " + thThread.GetHashCode(); 
 
                                    thThread.Start(); 
 
 
                                    
// Increment the thread pool count 
 
                                    IncCurThreadsInPool(); 
 
                                }
 
 
                            }
 
 
                        }
 
 
                    }
 
 
                    
catch 
                    

 
                    }
 
 
 
                    
// Relase the lock 
 
                    Monitor.Exit(GetCriticalSection); 
 
 
                    
// Increment the number of active threads 
 
                    DecActThreadsInPool(); 
 
                }
 
 
            }
 
 
 
            
catch(Exception ex) 
            

                
string str=ex.Message; 
 
            }
 
 
 
            
// Decrement the thread pool count 
 
            DecCurThreadsInPool(); 
 
        }
 
 
        
//public void PostEvent(Int32 iValue 
        public void PostEvent(int iValue) 
        

 
            
try 
            

 
                
// Only add work if we are not disposing 
 
                
if (IsDisposed == false
                

 
                    
unsafe 
                    

 
                        
// Post an event into the IOCP Thread Pool 
 
                        PostQueuedCompletionStatus(GetHandle, 
4, (UInt32*) iValue, null); 
 
                    }
 
 
 
                    
// Increment the number of item of work 
 
                    IncCurWorkInPool(); 
 
 
                    
// Get a lock 
 
                    Monitor.Enter(GetCriticalSection); 
 
 
                    
try 
                    

 
                        
// If we have less than max threads currently in the pool 
 
                        
if (GetCurThreadsInPool < GetMaxThreadsInPool) 
                        

 
                            
// Should we add a new thread to the pool 
 
                            
if (GetActThreadsInPool == GetCurThreadsInPool) 
                            

 
                                
if (IsDisposed == false
                                

 
                                    
// Create a thread and start it 
 
                                    ThreadStart tsThread 
= new ThreadStart(IOCPFunction); 
 
                                    Thread thThread 
= new Thread(tsThread); 
 
                                    thThread.Name 
= "IOCP " + thThread.GetHashCode(); 
 
                                    thThread.Start(); 
 
 
                                    
// Increment the thread pool count 
 
                                    IncCurThreadsInPool(); 
 
                                }
 
 
                            }
 
 
                        }
 
 
                    }
 
 
 
                    
catch 
                    

 
                    }
 
 
 
                    
// Release the lock 
 
                    Monitor.Exit(GetCriticalSection); 
 
                }
 
 
            }
 
 
 
            
catch (Exception e) 
            

 
                
throw e; 
 
            }
 
 
 
            
catch 
            

 
                
throw new Exception("Unhandled Exception"); 
 
            }
 
 
        }
   
 
        
public void PostEvent() 
        

 
            
try 
            

 
                
// Only add work if we are not disposing 
 
                
if (IsDisposed == false
                

 
                    
unsafe 
                    

 
                        
// Post an event into the IOCP Thread Pool 
 
                        PostQueuedCompletionStatus(GetHandle, 
0nullnull); 
 
                    }
 
 
 
                    
// Increment the number of item of work 
 
                    IncCurWorkInPool(); 
 
 
                    
// Get a lock 
 
                    Monitor.Enter(GetCriticalSection); 
 
 
                    
try 
 
                    

 
                        
// If we have less than max threads currently in the pool 
 
                        
if (GetCurThreadsInPool < GetMaxThreadsInPool) 
 
                        

 
                            
// Should we add a new thread to the pool 
 
                            
if (GetActThreadsInPool == GetCurThreadsInPool) 
 
                            

 
                                
if (IsDisposed == false
 
                                

 
                                    
// Create a thread and start it 
 
                                    ThreadStart tsThread 
= new ThreadStart(IOCPFunction); 
 
                                    Thread thThread 
= new Thread(tsThread); 
 
                                    thThread.Name 
= "IOCP " + thThread.GetHashCode(); 
 
                                    thThread.Start(); 
 
 
                                    
// Increment the thread pool count 
 
                                    IncCurThreadsInPool(); 
 
                                }
 
 
                            }
 
 
                        }
 
 
                    }
 
 
 
                    
catch 
 
                    

 
                    }
 
 
 
                    
// Release the lock 
 
                    Monitor.Exit(GetCriticalSection); 
 
                }
 
 
            }
 
 
            
catch 
 
            

 
                
throw new Exception("Unhandled Exception"); 
 
            }
 
 
        }
 
 
    }
 
 
}
 
目录
相关文章
|
数据采集 算法 数据管理
频标频稳比对测试系统重新定义测量边界
在上海张江实验室的超净间里,一束激光正以每秒 30 万公里的速度穿越真空腔,与原子跃迁频率进行着纳米级的较量。而在千里之外的西安高新区,一台黑色金属机箱内,SYN5609A 型频标比对测量系统正以同样的精度,为这场量子级的时间竞赛提供着基准坐标。这台看似普通的仪器,正在用双混频时差技术,将人类对时间的掌控精度推向新的维度。
|
开发框架 .NET C#
C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
【10月更文挑战第9天】在 C#/.NET Core 中,有多种方法可以删除字符串的最后一个字符,包括使用 `Substring` 方法、`Remove` 方法、`ToCharArray` 与 `Array.Copy`、`StringBuilder`、正则表达式、循环遍历字符数组以及使用 LINQ 的 `SkipLast` 方法。
625 8
|
存储 C# 索引
C# 一分钟浅谈:数组与集合类的基本操作
【9月更文挑战第1天】本文详细介绍了C#中数组和集合类的基本操作,包括创建、访问、遍历及常见问题的解决方法。数组适用于固定长度的数据存储,而集合类如`List<T>`则提供了动态扩展的能力。文章通过示例代码展示了如何处理索引越界、数组长度不可变及集合容量不足等问题,并提供了解决方案。掌握这些基础知识可使程序更加高效和清晰。
412 6
|
数据采集 自然语言处理 数据库
深入体验阿里云通义灵码:测试与实例展示
阿里云通义灵码是一款强大的代码生成工具,支持自然语言描述需求,快速生成高质量代码。它在测试、代码质量和用户体验方面表现出色,能够高效地生成 Python 和 Java 等语言的代码,助力开发者提升开发效率和代码质量。无论是新手还是资深开发者,都能从中受益匪浅。
深入体验阿里云通义灵码:测试与实例展示
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
1579 12
|
机器学习/深度学习 JSON 算法
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
本文详细介绍了使用YOLOv5-Seg模型进行图像分割的完整流程,包括图像分割的基础知识、YOLOv5-Seg模型的特点、环境搭建、数据集准备、模型训练、验证、测试以及评价指标。通过实例代码,指导读者从自定义数据集开始,直至模型的测试验证,适合深度学习领域的研究者和开发者参考。
7437 3
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
|
测试技术 开发者
vertx的学习总结6之动态代理类和测试
本文是Vert.x学习系列的第六部分,介绍了如何使用动态代理在事件总线上公开服务,以及如何进行Vert.x组件的异步测试,包括动态代理的创建和使用,以及JUnit 5和Vert.x测试工具的结合使用。
260 3
vertx的学习总结6之动态代理类和测试
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
391 5
|
安全 C# 索引
C#一分钟浅谈:属性与索引器的定义
本文深入浅出地介绍了C#编程中的属性和索引器。属性让字段更安全,通过访问器方法在读写时执行额外操作,如验证数据有效性;索引器则赋予类数组般的访问方式,支持基于索引的数据访问模式。文章通过示例代码展示了如何定义及使用这两种特性,并提供了常见问题及其解决方案,帮助读者写出更健壮、易维护的代码。希望读者能从中学习到如何有效利用属性和索引器增强C#类的功能性。
470 12
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
394 2