public async Task UnsubscribeAsync(string channel, CancellationToken cancellationToken = default) { if (_ws.NativeClient?.State != WebSocketState.Open) { // try reconnect or refresh, otherwise throw ex return; } if (!_authorized) { // try reconnect or refresh, otherwise throw ex return; } if (_channels.TryRemove(channel, out var subscription)) { var unsubscribeCommand = new Command { Id = InterlockedEx.Increment(ref _nextOperationId), Method = MethodType.Unsubscribe, Params = new UnsubscribeRequest { Channel = channel }.ToByteString() }; await HandleCommand(unsubscribeCommand, cancellationToken); subscription.State = SubscriptionState.Unsubscribed; subscription.UnsubscribedEventSource?.OnNext(new UnsubscribedEvent(subscription.Channel, false)); subscription.Dispose(); } }
/// <summary> /// Implements the ResourceLock's DoneWriting behavior. /// </summary> protected override void OnLeave(Boolean exclusive) { // Pre-condition: Lock's state must be Owned // Post-condition: Lock's state must become Free (the lock is never passed) // Phase 1: Free the lock Int32 ls = InterlockedEx.And(ref m_LockState, ~c_lsOwned); if (ls == c_lsOwned) { StressPause(); // If no waiters, nothing to do, we can just return } else { // Phase 2: Possibly wake waiters // If lock is free, try to subtract 1 from the number of waiters ls &= ~c_lsOwned; if (IfThen(ref m_LockState, ls, ls - c_1Waiter)) { StressPause(); // We sucessfully subtracted 1, wake 1 waiter m_WaiterLock.Release(1); StressPause(); } else { // Lock's state changed by other thread, other thread will deal with it StressPause(); } } }
///<summary>Derived class overrides <c>OnEnter</c> to provide specific reader locking semantics.</summary> protected override void OnEnter(Boolean exclusive) { if (exclusive) { Interlocked.Increment(ref m_WriteRequests); Interlocked.Increment(ref m_WritersWaiting); Int64 startTime = Environment.TickCount; InnerLock.Enter(exclusive); // Only 1 thread is writing, so no thread safety is required here m_WriterMaxWaitTime = Math.Max(m_WriterMaxWaitTime, checked ((Int64)(Environment.TickCount - startTime))); Interlocked.Decrement(ref m_WritersWaiting); Interlocked.Increment(ref m_WritersWriting); m_WriterStartHoldTime = Environment.TickCount; } else { Interlocked.Increment(ref m_ReadRequests); Interlocked.Increment(ref m_ReadersWaiting); Int64 startTime = Environment.TickCount; InnerLock.Enter(exclusive); InterlockedEx.Max(ref m_ReaderMaxWaitTime, checked ((Int64)(Environment.TickCount - startTime))); Interlocked.Decrement(ref m_ReadersWaiting); Interlocked.Increment(ref m_ReadersReading); Monitor.Enter(m_ReaderStartHoldTime); m_ReaderStartHoldTime.Add(Thread.CurrentThread.ManagedThreadId, Environment.TickCount); Monitor.Exit(m_ReaderStartHoldTime); } }
///<summary>Derived class overrides <c>OnDoneReading</c> to provide specific reader unlocking semantics.</summary> ///<remarks>You do not need to override this method if the specific lock provides mutual-exclusive locking semantics.</remarks> protected override void OnLeave(Boolean write) { if (write) { // Only 1 thread is writing, so no thread safety is required here Int64 HoldTime = checked ((Int64)(Environment.TickCount - m_WriterStartHoldTime)); m_WriterMinHoldTime = Math.Min(m_WriterMinHoldTime, HoldTime); m_WriterMaxHoldTime = Math.Max(m_WriterMaxHoldTime, HoldTime); m_WritersWriting--; m_WritersDone++; InnerLock.Leave(); } else { Int32 threadId = Thread.CurrentThread.ManagedThreadId; Int64 HoldTime = checked ((Int64)(Environment.TickCount - m_ReaderStartHoldTime[threadId])); Monitor.Enter(m_ReaderStartHoldTime); m_ReaderStartHoldTime.Remove(threadId); Monitor.Exit(m_ReaderStartHoldTime); InterlockedEx.Min(ref m_ReaderMinHoldTime, HoldTime); InterlockedEx.Max(ref m_ReaderMaxHoldTime, HoldTime); Interlocked.Decrement(ref m_ReadersReading); Interlocked.Increment(ref m_ReadersDone); InnerLock.Leave(); } }
/// <summary> /// Sets the event. /// </summary> public void Set() { // 1. Value = 1. // 2. Event = Global Event. // 3. Set Event. // 4. [Optional] Dereference the Global Event. if ((InterlockedEx.Or(ref _value, EventSet) & EventSet) != 0) { return; } RefEvent(); // Do an update-to-date read. CEvent localEvent = _event; // Set the event if we had one. if (localEvent != null) { localEvent.Set(); } // Note that at this point we don't need to worry about anyone // creating the event and waiting for it, because if they did // they would check the value first. It would be 1, so they // wouldn't wait at all. DerefEvent(); }
/// <summary> /// Implements the ResourceLock's WaitToWrite behavior. /// </summary> protected override void OnEnter(Boolean exclusive) { while (true) { // Turn on the "owned" bit Int32 ls = InterlockedEx.Or(ref m_LockState, c_lsOwned); StressPause(); // If lock was free, this thread got it, return if ((ls & c_lsOwned) == c_lsFree) { return; } StressPause(); // Another thread owned the lock, add 1 waiter if (IfThen(ref m_LockState, ls, ls + c_1Waiter)) { // If successfully added 1, wait for lock m_WaiterLock.WaitOne(); StressPause(); } // We weren't able to add 1 waiter or waiter woke, attempt to get the lock StressPause(); } }
public void TestInterlockedEx() { var intVal = int.MinValue; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref intVal, newValue: int.MaxValue, oldValue: int.MinValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref intVal, newValue: int.MaxValue, oldValue: int.MinValue)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref intVal, newValue: int.MinValue, oldValue: int.MaxValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref intVal, newValue: int.MinValue, oldValue: int.MaxValue)); var longVal = long.MinValue; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref longVal, newValue: long.MaxValue, oldValue: long.MinValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref longVal, newValue: long.MaxValue, oldValue: long.MinValue)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref longVal, newValue: long.MinValue, oldValue: long.MaxValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref longVal, newValue: long.MinValue, oldValue: long.MaxValue)); var floatVal = float.MinValue; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref floatVal, newValue: float.MaxValue, oldValue: float.MinValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref floatVal, newValue: float.MaxValue, oldValue: float.MinValue)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref floatVal, newValue: float.MinValue, oldValue: float.MaxValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref floatVal, newValue: float.MinValue, oldValue: float.MaxValue)); var doubleVal = double.MinValue; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref doubleVal, newValue: double.MaxValue, oldValue: double.MinValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref doubleVal, newValue: double.MaxValue, oldValue: double.MinValue)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref doubleVal, newValue: double.MinValue, oldValue: double.MaxValue)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref doubleVal, newValue: double.MinValue, oldValue: double.MaxValue)); var object1 = new object(); var object2 = new object(); var objectVal = object1; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref objectVal, newValue: object2, oldValue: object1)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref objectVal, newValue: object2, oldValue: object1)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref objectVal, newValue: object1, oldValue: object2)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref objectVal, newValue: object1, oldValue: object2)); var intPtr1 = new IntPtr(long.MinValue); var intPtr2 = new IntPtr(long.MaxValue); var intPtrVal = intPtr1; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref intPtrVal, newValue: intPtr2, oldValue: intPtr1)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref intPtrVal, newValue: intPtr2, oldValue: intPtr1)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref intPtrVal, newValue: intPtr1, oldValue: intPtr2)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref intPtrVal, newValue: intPtr1, oldValue: intPtr2)); var tuple1 = Tuple.Create(int.MinValue, long.MinValue, float.MinValue, double.MinValue); var tuple2 = Tuple.Create(int.MaxValue, long.MaxValue, float.MaxValue, double.MaxValue); var tuple = tuple1; Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref tuple, newValue: tuple2, oldValue: tuple1)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref tuple, newValue: tuple2, oldValue: tuple1)); Assert.IsTrue(InterlockedEx.TryCompareExchange(location1: ref tuple, newValue: tuple1, oldValue: tuple2)); Assert.IsFalse(InterlockedEx.TryCompareExchange(location1: ref tuple, newValue: tuple1, oldValue: tuple2)); }
static void Main() { Foo x = Foo.X; Foo y = Foo.Y; y = InterlockedEx.CompareExchangeEnum(ref x, y, Foo.X); Console.WriteLine("x: " + x); Console.WriteLine("y: " + y); }
/// <summary> /// Dereferences the event, closing it if necessary. /// </summary> private void DerefEvent() { if ((InterlockedEx.Add(ref _value, -EventRefCountIncrement) >> EventRefCountShift) == 0) { if (_event != null) { _event.Close(); _event = null; } } }
/// <summary> /// Applies the transformation to a set of input vectors, /// producing an associated set of output vectors. /// </summary> /// <param name="input">The input data to which /// the transformation should be applied.</param> /// <param name="result">The location to where to store the /// result of this transformation.</param> /// <returns>The output generated by applying this /// transformation to the given input.</returns> public double[] Transform(TInput[] input, double[] result) { // Detect all activation centroids Parallel.For(0, input.Length, ParallelOptions, i => { int j = classifier.Decide(input[i]); InterlockedEx.Increment(ref result[j]); }); return(result); }
/// <summary> /// Applies the transformation to a set of input vectors, /// producing an associated set of output vectors. /// </summary> /// <param name="input">The input data to which /// the transformation should be applied.</param> /// <param name="result">The location to where to store the /// result of this transformation.</param> /// <returns>The output generated by applying this /// transformation to the given input.</returns> public double[] Transform(IList <TPoint> input, double[] result) { // Detect all activation centroids Parallel.For(0, input.Count, ParallelOptions, i => { TFeature x = input[i].Descriptor; int j = Clustering.Clusters.Decide(x); InterlockedEx.Increment(ref result[j]); }); return(result); }
public override void Free(LockFreeNode <T> node) { node.Item = default(T); // Allow early GC // Try to make the new node be the head of the stack do { // Make the new node refer to the old head node.Next = m_head.Next; // If previous head's next == what we thought was next, change head's Next to the new node // else, try again if another thread changed the head } while (!InterlockedEx.IfThen(ref m_head.Next, node.Next, node)); }
/// <summary> /// Applies the transformation to a set of input vectors, /// producing an associated set of output vectors. /// </summary> /// <param name="input">The input data to which /// the transformation should be applied.</param> /// <param name="result">The location to where to store the /// result of this transformation.</param> /// <returns>The output generated by applying this /// transformation to the given input.</returns> public double[] Transform(IEnumerable <TPoint> input, double[] result) { IList <TPoint> list = input.ToList(); // Detect all activation centroids Parallel.For(0, list.Count, ParallelOptions, i => { TFeature x = list[i].Descriptor; int j = classifier.Decide(x); InterlockedEx.Increment(ref result[j]); }); return(result); }
public Boolean TryDequeue(out T item) { item = default(T); // Loop until we manage to advance the head, removing // a node (if there are no nodes to dequeue, we'll exit the method instead) for (Boolean dequeuedNode = false; !dequeuedNode;) { // make local copies of the head, the tail, and the head's Next reference LockFreeNode <T> tempHead = m_head; LockFreeNode <T> tempTail = m_tail; LockFreeNode <T> tempHeadNext = tempHead.Next; // If another thread changed the head, start over Thread.MemoryBarrier(); // Make sure the value read from m_head is fresh if (tempHead != m_head) { continue; } // If the head equals the tail if (tempHead == tempTail) { // If the head node refers to null, then the queue is empty if (tempHeadNext == null) { return(false); } // The head refers to the tail whose Next is not null. This means // we have a lagging tail; update it InterlockedEx.IfThen(ref m_tail, tempTail, tempHeadNext); continue; } // The head and tail nodes are different; dequeue the head node and advance the head item = tempHeadNext.Item; dequeuedNode = InterlockedEx.IfThen(ref m_head, tempHead, tempHeadNext); if (dequeuedNode) { m_nodeManager.Free(tempHead); } } //Interlocked.Decrement(ref m_count); return(true); }
protected override void OnEnter(Boolean exclusive) { if (exclusive) { InnerLock.Enter(exclusive); VerifyNoWriters("Writing while already writing!"); VerifyNoReaders("Writing while already reading!"); InterlockedEx.BitTestAndSet(ref m_LockState, 31); // Add the writer } else { InnerLock.Enter(exclusive); VerifyNoWriters("Reading while already writing!"); // Sanity check for no writers Interlocked.Increment(ref m_LockState); // Add a reader } }
protected override void OnLeave(Boolean write) { if (write) { VerifyOneWriter("Done writing while not writing!"); VerifyNoReaders("Done writing while already reading!"); InterlockedEx.BitTestAndReset(ref m_LockState, 31); // Remove the writer } else { VerifySomeReaders("Done reading while not reading!"); VerifyNoWriters("Done reading while already writing!"); Interlocked.Decrement(ref m_LockState); // Subtract a reader } InnerLock.Leave(); }
public async Task SubscribeAsync(Subscription subscription, CancellationToken cancellationToken = default) { subscription.State = SubscriptionState.Subscribing; // если канал уже есть, нельзя давать повторно регаться. if (_ws.NativeClient?.State != WebSocketState.Open || !_authorized) { subscription.State = SubscriptionState.SubscriptionError; subscription.SubscriptionErrorEventSource?.OnNext(new SubscriptionErrorEvent(subscription.Channel)); // TODO: exceptions throw new Exception(); } var offset = subscription.Offset; subscription.Offset = InterlockedEx.Increment(ref offset); var subscribeCommand = new Command { Id = InterlockedEx.Increment(ref _nextOperationId), Method = MethodType.Subscribe, Params = new SubscribeRequest { Channel = subscription.Channel, Offset = subscription.Offset, Recover = false, Token = _token, }.ToByteString() }; try { await HandleCommand(subscribeCommand, cancellationToken); subscription.State = SubscriptionState.Subscribed; subscription.SubscribedEventSource?.OnNext(new SubscribedEvent(subscription.Channel)); } catch (CentrifugoException e) { subscription.State = SubscriptionState.SubscriptionError; subscription.SubscriptionErrorEventSource?.OnNext(new SubscriptionErrorEvent(subscription.Channel, e)); throw; } }
private Int32 NumReadersToWake() { Int32 ls = m_LockState, numReadersWaiting; // If lock is Free && RW>0, try to subtract all readers while ((State(ls) == OneManyLockStates.Free) && ((numReadersWaiting = NumReadersWaiting(ls)) > 0)) { Int32 desired = ls; DecReadersWaiting(ref desired, numReadersWaiting); if (InterlockedEx.IfThen(ref m_LockState, ls, desired, out ls)) { // We sucessfully subtracted all waiting readers, wake them up return(numReadersWaiting); } } return(0); }
private Int32 NumWritersToWake() { Int32 ls = m_LockState; // If lock is RFW && WW>0, try to subtract 1 writer while ((State(ls) == OneManyLockStates.ReservedForWriter) && (NumWritersWaiting(ls) > 0)) { Int32 desired = ls; DecWritersWaiting(ref desired); if (InterlockedEx.IfThen(ref m_LockState, ls, desired, out ls)) { // We sucessfully subtracted 1 waiting writer, wake it up return(1); } } return(0); }
/// <summary> /// Опубликовать в канал массив байт сообщения. /// </summary> /// <param name="channel">Наименование канала.</param> /// <param name="payload">Тело сообщения.</param> public async Task PublishAsync(string channel, ReadOnlyMemory <byte> payload) { var publishCommand = new Command { Id = InterlockedEx.Increment(ref _nextOperationId), Method = MethodType.Publish, Params = new PublishRequest { Channel = channel, Data = ByteString.CopyFrom(payload.Span) }.ToByteString() }; await HandleCommand( publishCommand, CancellationToken.None ); }
// If two threads call Enqueue simultaneously: // Both threads create and initialize a new node // The tail's Next will refer to one of these 2 new nodes // The new new tail's Next will refer to the other of the 2 new nodes // m_tail will refer to the 1st new node appended (not the real tail) // To fix this: Enqueue initializes by advancing m_tail to the node whose Next is null public void Enqueue(T item) { // Get (or allocate) a node and initialize it LockFreeNode <T> newNode = m_nodeManager.Allocate(item); LockFreeNode <T> tempTail = null; for (Boolean appendedNewNode = false; !appendedNewNode;) { // Get the current tail and what IT refers to tempTail = m_tail; LockFreeNode <T> tempTailNext = tempTail.Next; // If another thread changed the tail, start over Thread.MemoryBarrier(); // Make sure the value read from m_tail is fresh if (tempTail != m_tail) { continue; } // If the tail isn't truely the tail, fix the tail, start over if (tempTailNext != null) { // This can happen if multiple threads append nodes at the same time // A new node thinks it's the tail (Next is null) as another thread's new node // updates the previous node's Nextthinks it's the tail's Next field may not InterlockedEx.IfThen(ref m_tail, tempTail, tempTailNext); continue; } // The tail is truely the tail, try to append the new node appendedNewNode = InterlockedEx.IfThen(ref tempTail.Next, null, newNode); } // When new node is sucessfully appended, make the tail refer to it // This can fail if another thread scoots in. If this happens, our node is // appended to the linked-list but m_tail refers to another node that is not // the tail. The next Enqueue/Dequeue call will fix m_tail InterlockedEx.IfThen(ref m_tail, tempTail, newNode); //Interlocked.Increment(ref m_count); }
private double[] DistanceByVoting(TInput input, double[] result, Cache cache) { Parallel.For(0, Indices.Length, ParallelOptions, k => { int i = Indices[k].Class1; int j = Indices[k].Class2; if (Classes.Decide(distance(i, j, input, cache))) { InterlockedEx.Increment(ref result[i]); } else { InterlockedEx.Increment(ref result[j]); } }); return(result); }
private double[] DistanceByVoting(TInput input, double[] result) { Parallel.For(0, indices.Length, options, k => { int i = indices[k].Class1; int j = indices[k].Class2; if (Models[i - 1][j].Decide(input)) { InterlockedEx.Increment(ref result[i]); } else { InterlockedEx.Increment(ref result[j]); } }); return(result); }
public override LockFreeNode <T> Allocate(T item) { LockFreeNode <T> node; do { // Get head node = m_head.Next; // If no head, stack is empty, return new node if (node == null) { return(new LockFreeNode <T>(item)); } // If previous head == what we think is head, change head to next node // else try again } while (!InterlockedEx.IfThen(ref m_head.Next, node, node.Next)); node.Item = item; return(node); }
/// <summary> /// Implements the ResourceLock's WaitToWrite behavior. /// </summary> protected override void OnEnter(Boolean exclusive) { if (exclusive) { // Indicate that a writer wants to write: WP++ Interlocked.Add(ref m_LockState, c_1WritersPending); StressPause(); // OK to write if no readers are reading and // no writers are pending: RR=0, WP=don't care, WW=0 // Set the Writer is writing bit on. InterlockedEx.MaskedOr(ref m_LockState, c_lsOwnedByWriter, c_WritersPendingMask); } else { // OK to read if no writers are waiting: RR=don't care, WP=0, WW=0 // If we're good, add 1 to the RR InterlockedEx.MaskedAdd(ref m_LockState, c_1ReadersReading, c_ReadersReadingMask); } StressPause(); }
public async Task ConnectAsync(CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(_token)) { throw new InvalidOperationException("Токен не установлен"); } if (_ws.NativeClient?.State == WebSocketState.Open && _authorized) { return; } await _ws.StartOrFail(); var connectCommand = new Command { Id = InterlockedEx.Increment(ref _nextOperationId), Method = MethodType.Connect, Params = new ConnectRequest { Token = _token }.ToByteString() }; // TODO: retry with exponential backoff, reinit connection on connection lost var response = await HandleCommand(connectCommand, cancellationToken); var connectResult = ConnectResult.Parser.ParseFrom(response); _authorized = true; //_clientId = authResult.Client; _connectedEventSource.OnNext(new ConnectedEvent { Client = Guid.Parse(connectResult.Client), Expires = connectResult.Expires, Ttl = connectResult.Ttl, Version = connectResult.Version }); }
/// <summary> /// Applies the transformation to a set of input vectors, /// producing an associated set of output vectors. /// </summary> /// <param name="input">The input data to which /// the transformation should be applied.</param> /// <param name="result">The location to where to store the /// result of this transformation.</param> /// <returns>The output generated by applying this /// transformation to the given input.</returns> public double[] Transform(TInput[] input, double[] result) { // Detect all activation centroids if (ParallelOptions.MaxDegreeOfParallelism == 1) { for (int i = 0; i < input.Length; i++) { int j = classifier.Decide(input[i]); result[j]++; } ; } else { Parallel.For(0, input.Length, ParallelOptions, i => { int j = classifier.Decide(input[i]); InterlockedEx.Increment(ref result[j]); }); } return(result); }
public int Release(int count) { #if USE_FAST_EVENT if (m_isClosed) #else if (m_gate == null) #endif { throw new ObjectDisposedException("Semaphore already closed"); } if (count < 1) { throw new ArgumentOutOfRangeException("count", "count must be > 0"); } int cc = m_currentCount; if (InterlockedEx.Add(ref m_currentCount, count) > m_maximumCount) { throw new SemaphoreFullException("count exceeded maximum count"); } m_gate.Set(); //Open gate return(cc); }
private void AddThreadIdWithRecurseCountOf1(Int32 callingThreadId) { Contract.Assume(m_ReaderThreadIdsAndRecurseCounts != null); // The JITter produces more efficient code if we load the array reference into a temporary ThreadIdAndRecurseCount[] readerThreadIdsAndRecurseCounts = m_ReaderThreadIdsAndRecurseCounts; for (Int32 index = 0; index < readerThreadIdsAndRecurseCounts.Length; index++) { if (readerThreadIdsAndRecurseCounts[index].m_Id == 0) { if (InterlockedEx.IfThen(ref readerThreadIdsAndRecurseCounts[index].m_Id, 0, callingThreadId)) { readerThreadIdsAndRecurseCounts[index].m_Count = 1; return; } else { // We found a slot but then it was taken away from us index = -1; // Start the search over again from the beginning continue; } } } throw new InvalidOperationException("More current reader threads than allowed!"); }
public GoldCalculator(IUserSubAccountBll subAccountBll, IUserBll userBll, IHangUpTimeBll hangUpTimeBll) { _subAccountBll = subAccountBll; _userBll = userBll; _hangUpTimeBll = hangUpTimeBll; _creator = userId => { return(_subAccountBll.Count(userId)); }; _timer = new Timer(obj => { if (InterlockedEx.IfThen(ref _isExecuted, 1, 1)) { return; } Interlocked.Increment(ref _isExecuted); try { foreach (var sessionId in Global.GetConnectedClientUserId()) { if (sessionId.LastCalcTime.Value.AddMinutes(10) <= DateTime.Now) { _hangUpTimeBll.Add(new HangUpTime { UserId = sessionId.Id, Minutes = 10 }); var count = CacheManager.GetSubAccountCount(sessionId.Id, _creator); int gold = 0; if (count == 1) { gold = 5; } else if (count == 2) { gold = 8; } else if (count >= 3) { gold = 13; } if (gold != 0) { _userBll.UpdateGold(sessionId.Id, gold); } sessionId.LastCalcTime = sessionId.LastCalcTime.Value.AddMinutes(10); } } } catch (Exception ex) { Global.Resolve <ILoggerFactory>() .GetCurrentClassLogger() .ErrorException("GoldCalculator Timer Callback.", ex); } finally { Interlocked.Decrement(ref _isExecuted); } }, null, Timeout.Infinite, CalculatePeriod); }