/// <summary>Rents a <see cref="Int32TaskSocketAsyncEventArgs"/> for immediate use.</summary> /// <param name="isReceive">true if this instance will be used for a receive; false if for sends.</param> private Int32TaskSocketAsyncEventArgs RentSocketAsyncEventArgs(bool isReceive) { // Get any cached SocketAsyncEventArg we may have. CachedTaskEventArgs cea = LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs); Int32TaskSocketAsyncEventArgs saea = isReceive ? Interlocked.Exchange(ref cea.Receive, s_rentedInt32Sentinel) : Interlocked.Exchange(ref cea.Send, s_rentedInt32Sentinel); if (saea == s_rentedInt32Sentinel) { // An instance was once created (or is currently being created elsewhere), but some other // concurrent operation is using it. Since we can store at most one, and since an individual // APM operation is less expensive than creating a new SAEA and using it only once, we simply // return null, for a caller to fall back to using an APM implementation. return(null); } if (saea == null) { // No instance has been created yet, so create one. saea = new Int32TaskSocketAsyncEventArgs(); saea.Completed += isReceive ? ReceiveCompletedHandler : SendCompletedHandler; } return(saea); }
/// <summary>Dispose of any cached <see cref="Int32TaskSocketAsyncEventArgs"/> instances.</summary> private void DisposeCachedTaskSocketAsyncEventArgs() { CachedTaskEventArgs cea = _cachedTaskEventArgs; if (cea != null) { Interlocked.Exchange(ref cea.Accept, s_rentedSocketSentinel)?.Dispose(); Interlocked.Exchange(ref cea.Receive, s_rentedInt32Sentinel)?.Dispose(); Interlocked.Exchange(ref cea.Send, s_rentedInt32Sentinel)?.Dispose(); } }