(转)C#实现IOCP

C#实现IOCP(完成端口)的详细代码如下:

 
 
using System;
using System.Threading; // Included for the Thread.Sleep call
using Continuum.Threading;
namespace Sample
{
// ============================================
/// <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( 0 , 5 , 10 , new IOCPThreadPool.USER_FUNCTION(IOCPThreadFunction));
pThreadPool.PostEvent(
10 );
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(Int32 iValue)
{
try
{
Console.WriteLine(
" Value: {0} " , iValue);
}
catch (Exception pException)
{
Console.WriteLine(pException.Message);
}
}
}
}

using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace Continuum.Threading
{

// Structures
// ==========================================
/// <summary> This is the WIN32 OVERLAPPED structure </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public unsafe struct OVERLAPPED
{
UInt32
* ulpInternal;
UInt32
* ulpInternalHigh;
Int32 lOffset;
Int32 lOffsetHigh;
UInt32 hEvent;
}

// Classes
// ============================================
/// <summary> This class provides the ability to create a thread pool to manage work. The
/// class abstracts the Win32 IOCompletionPort API so it requires the use of
/// unmanaged code. Unfortunately the .NET framework does not provide this functionality </summary>
public sealed class IOCPThreadPool
{

// Win32 Function Prototypes
/// <summary> Win32Func: Create an IO Completion Port Thread Pool </summary>
[DllImport( " Kernel32 " , CharSet = CharSet.Auto)]
private unsafe static extern UInt32 CreateIoCompletionPort(UInt32 hFile, UInt32 hExistingCompletionPort, UInt32 * puiCompletionKey, UInt32 uiNumberOfConcurrentThreads);

/// <summary> Win32Func: Closes an IO Completion Port Thread Pool </summary>
[DllImport( " Kernel32 " , CharSet = CharSet.Auto)]
private unsafe static extern Boolean CloseHandle(UInt32 hObject);

/// <summary> Win32Func: Posts a context based event into an IO Completion Port Thread Pool </summary>
[DllImport( " Kernel32 " , CharSet = CharSet.Auto)]
private unsafe static extern Boolean PostQueuedCompletionStatus(UInt32 hCompletionPort, UInt32 uiSizeOfArgument, UInt32 * puiUserArg, OVERLAPPED * pOverlapped);

/// <summary> Win32Func: Waits on a context based event from an IO Completion Port Thread Pool.
/// All threads in the pool wait in this Win32 Function </summary>
[DllImport( " Kernel32 " , CharSet = CharSet.Auto)]
private unsafe static extern Boolean GetQueuedCompletionStatus(UInt32 hCompletionPort, UInt32 * pSizeOfArgument, UInt32 * puiUserArg, OVERLAPPED ** ppOverlapped, UInt32 uiMilliseconds);

// Constants
/// <summary> SimTypeConst: This represents the Win32 Invalid Handle Value Macro </summary>
private const UInt32 INVALID_HANDLE_VALUE = 0xffffffff ;

/// <summary> SimTypeConst: This represents the Win32 INFINITE Macro </summary>
private const UInt32 INIFINITE = 0xffffffff ;

/// <summary> SimTypeConst: This tells the IOCP Function to shutdown </summary>
private const Int32 SHUTDOWN_IOCPTHREAD = 0x7fffffff ;



// Delegate Function Types
/// <summary> DelType: This is the type of user function to be supplied for the thread pool </summary>
public delegate void USER_FUNCTION(Int32 iValue);


// Private Properties
private UInt32 m_hHandle;
/// <summary> SimType: Contains the IO Completion Port Thread Pool handle for this instance </summary>
private UInt32 GetHandle { get { return m_hHandle; } set { m_hHandle = value; } }

private Int32 m_uiMaxConcurrency;
/// <summary> SimType: The maximum number of threads that may be running at the same time </summary>
private Int32 GetMaxConcurrency { get { return m_uiMaxConcurrency; } set { m_uiMaxConcurrency = value; } }

private Int32 m_iMinThreadsInPool;
/// <summary> SimType: The minimal number of threads the thread pool maintains </summary>
private Int32 GetMinThreadsInPool { get { return m_iMinThreadsInPool; } set { m_iMinThreadsInPool = value; } }

private Int32 m_iMaxThreadsInPool;
/// <summary> SimType: The maximum number of threads the thread pool maintains </summary>
private Int32 GetMaxThreadsInPool { get { return m_iMaxThreadsInPool; } set { m_iMaxThreadsInPool = value; } }

private Object m_pCriticalSection;
/// <summary> RefType: A serialization object to protect the class state </summary>
private Object GetCriticalSection { get { return m_pCriticalSection; } set { m_pCriticalSection = value; } }

private USER_FUNCTION m_pfnUserFunction;
/// <summary> DelType: A reference to a user specified function to be call by the thread pool </summary>
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; } }

// Public Properties
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); }



// Constructor, Finalize, and Dispose
// ***********************************************
/// <summary> Constructor </summary>
/// <param name = "iMaxConcurrency"> SimType: Max number of running threads allowed </param>
/// <param name = "iMinThreadsInPool"> SimType: Min number of threads in the pool </param>
/// <param name = "iMaxThreadsInPool"> SimType: Max number of threads in the pool </param>
/// <param name = "pfnUserFunction"> DelType: Reference to a function to call to perform work </param>
/// <exception cref = "Exception"> Unhandled Exception </exception>
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, 0 , null , (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 " );
}
}

// ***********************************************
/// <summary> Finalize called by the GC </summary>
~ IOCPThreadPool()
{
if ( ! IsDisposed)
Dispose();
}

// **********************************************
/// <summary> Called when the object will be shutdown. This
/// function will wait for all of the work to be completed
/// inside the queue before completing </summary>
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 Methods
// *******************************************
/// <summary> IOCP Worker Function that calls the specified user function </summary>
private void IOCPFunction()
{
UInt32 uiNumberOfBytes;
Int32 iValue;
try
{
while ( true )
{
unsafe
{
OVERLAPPED
* 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
{
}
// 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
{
}
// Decrement the thread pool count
DecCurThreadsInPool();
}

// Public Methods
// ******************************************
/// <summary> IOCP Worker Function that calls the specified user function </summary>
/// <param name="iValue"> SimType: A value to be passed with the event </param>
/// <exception cref = "Exception"> Unhandled Exception </exception>
public void PostEvent(Int32 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 " );
}
}
// *****************************************
/// <summary> IOCP Worker Function that calls the specified user function </summary>
/// <exception cref = "Exception"> Unhandled Exception </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, 0 , null , 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 " );
}
}
}
}

以上就是C#实现IOCP(完成端口)的详细代码示例,希望对你有所帮助。

转载于:https://www.cnblogs.com/lscy/archive/2010/10/20/1856535.html

最近有项目要做一个高性能网络服务器,去网络上搜到到的都是C++版本而且是英文或者简单的DEMO,所以自己动手写了C# 的DEMO。 网络上只写接收到的数据,没有说怎么处理缓冲区数据,本DEMO简单的介绍如何处理接收到的数据。简单易用,希望对大家有用. 1、在C#中,不用去面对完成端口的操作系统内核对象,Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用。请参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1。 2、我的SocketAsyncEventArgsPool类使用List对象来存储对客户端来通信的SocketAsyncEventArgs对象,它相当于直接使用内核对象时的IoContext。我这样设计比用堆栈来实现的好处理是,我可以在SocketAsyncEventArgsPool池中找到任何一个与服务器连接的客户,主动向它发信息。而用堆栈来实现的话,要主动给客户发信息,则还要设计一个结构来存储已连接上服务器的客户。 3、对每一个客户端不管还发送还是接收,我使用同一个SocketAsyncEventArgs对象,对每一个客户端来说,通信是同步进行的,也就是说服务器高度保证同一个客户连接上要么在投递发送请求,并等待;或者是在投递接收请求,等待中。本例只做echo服务器,还未考虑由服务器主动向客户发送信息。 4、SocketAsyncEventArgs的UserToken被直接设定为被接受的客户端Socket。 5、没有使用BufferManager 类,因为我在初始化时给每一个SocketAsyncEventArgsPool中的对象分配一个缓冲区,发送时使用Arrary.Copy来进行字符拷贝,不去改变缓冲区的位置,只改变使用的长度,因此在下次投递接收请求时恢复缓冲区长度就可以了!如果要主动给客户发信息的话,可以new一个SocketAsyncEventArgs对象,或者在初始化中建立几个来专门用于主动发送信息,因为这种需求一般是进行信息群发,建立一个对象可以用于很多次信息发送,总体来看,这种花销不大,还减去了字符拷贝和消耗。 6、测试结果:(在我的笔记本上时行的,我的本本是T420 I7 8G内存) 100客户 100,000(十万次)不间断的发送接收数据(发送和接收之间没有Sleep,就一个一循环,不断的发送与接收) 耗时3004.6325 秒完成 总共 10,000,000 一千万次访问 平均每分完成 199,691.6 次发送与接收 平均每秒完成 3,328.2 次发送与接收 整个运行过程中,内存消耗在开始两三分种后就保持稳定不再增涨。 看了一下对每个客户端的延迟最多不超过2秒。
1、在C#中,不用去面对完成端口的操作系统内核对象,Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用。请参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1。 2、我的SocketAsyncEventArgsPool类使用List对象来存储对客户端来通信的SocketAsyncEventArgs对象,它相当于直接使用内核对象时的IoContext。我这样设计比用堆栈来实现的好处理是,我可以在SocketAsyncEventArgsPool池中找到任何一个与服务器连接的客户,主动向它发信息。而用堆栈来实现的话,要主动给客户发信息,则还要设计一个结构来存储已连接上服务器的客户。 3、对每一个客户端不管还发送还是接收,我使用同一个SocketAsyncEventArgs对象,对每一个客户端来说,通信是同步进行的,也就是说服务器高度保证同一个客户连接上要么在投递发送请求,并等待;或者是在投递接收请求,等待中。本例只做echo服务器,还未考虑由服务器主动向客户发送信息。 4、SocketAsyncEventArgs的UserToken被直接设定为被接受的客户端Socket。 5、没有使用BufferManager 类,因为我在初始化时给每一个SocketAsyncEventArgsPool中的对象分配一个缓冲区,发送时使用Arrary.Copy来进行字符拷贝,不去改变缓冲区的位置,只改变使用的长度,因此在下次投递接收请求时恢复缓冲区长度就可以了!如果要主动给客户发信息的话,可以new一个SocketAsyncEventArgs对象,或者在初始化中建立几个来专门用于主动发送信息,因为这种需求一般是进行信息群发,建立一个对象可以用于很多次信息发送,总体来看,这种花销不大,还减去了字符拷贝和消耗。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值