/// <summary> /// Tries to lock the correlated todo instance with the specified scheduled date, true if locked, false, otherwise. /// Takes lock IF not enqueue, false otherwise /// </summary> private bool tryLockCorrelatedProcessing(string key, DateTime sd) { if (key == null) { key = string.Empty; } lock (m_CorrelationLocker) { _lck lck; if (!m_CorrelationLocker.TryGetValue(key, out lck)) { lck = new _lck { Date = sd, IsEnqueue = 0, IsProc = 1 }; m_CorrelationLocker.Add(key, lck); return(true); } if (lck.IsEnqueue == 0) { lck.IsProc++; if (sd > lck.Date) { lck.Date = sd; } return(true); } return(false);//lock is enqueue type } }
/* * Locking works as follows: * --------------------------- * All locking is done per CorrelationKey (different CorrelationKey do not inter-lock at all) * Within the same key: * * Any existing Enqueue lock blocks another Enqueue until existing is released * Any existing Enqueue lock returns FALSE for another Process until all Enqueue released * * Any existing Processing lock yields next date to Enqueue (+1 sec) * Any Exisiting Processing lock shifts next Date if another Processing lock is further advanced in time * * * Enqueue lock is reentrant for the same thread. * Processing lock is reentrant regardless of thread ownership * */ /// <summary> /// Returns the point in time AFTER which the enqueue operation may fetch correlated todos /// </summary> private DateTime lockCorrelatedEnqueue(string key, DateTime sd) { if (key == null) { key = string.Empty; } var ct = Thread.CurrentThread; uint spinCount = 0; while (true) { lock (m_CorrelationLocker) { _lck lck; if (!m_CorrelationLocker.TryGetValue(key, out lck)) { lck = new _lck { TEnqueue = ct, Date = sd, IsEnqueue = 1, IsProc = 0 }; m_CorrelationLocker.Add(key, lck); return(sd); } if (lck.IsEnqueue == 0) { lck.IsEnqueue = 1; lck.TEnqueue = ct; return(lck.Date.AddSeconds(1)); } if (lck.TEnqueue == ct)//if already acquired by this thread { lck.IsEnqueue++; if (sd < lck.Date) { lck.Date = sd; } return(lck.Date); } } if (spinCount < 100) { Thread.SpinWait(500); } else { Thread.Yield(); } unchecked { spinCount++; } } }