/// <summary> /// Unlock all the specified keys. /// </summary> /// <param name="cache"> /// The <see cref="IConcurrentCache"/> to use. /// </param> /// <param name="keys"> /// A collection of keys to unlock. /// </param> public static void UnlockAll(IConcurrentCache cache, ICollection keys) { foreach (var key in keys) { cache.Unlock(key); } }
/// <summary> /// Attempt to lock all the specified keys within a specified period /// of time. /// </summary> /// <param name="cache"> /// The <see cref="IConcurrentCache"/> to use. /// </param> /// <param name="keys"> /// A collection of keys to lock. /// </param> /// <param name="waitMillis"> /// The number of milliseconds to continue trying to obtain locks; /// pass zero to return immediately; pass -1 to block the calling /// thread until the lock could be obtained. /// </param> /// <returns> /// An <b>IList</b> containing all the locked keys in the order /// opposite to the locking order (LIFO); <c>null</c> if timeout has /// occurred. /// </returns> public static IList LockAll(IConcurrentCache cache, ICollection keys, int waitMillis) { // remove the duplicates HashSet setKeys = keys is HashSet ? (HashSet)keys : new HashSet(keys); // copy the keys into a list to fully control the iteration order var listKeys = new ArrayList(setKeys); var listLocked = new ArrayList(); int keysCount = listKeys.Count; bool isSuccess = true; do { int waitNextMillis = waitMillis; // allow blocking wait for the very first key for (int i = 0; i < keysCount; i++) { var key = listKeys[i]; isSuccess = cache.Lock(key, waitNextMillis); if (isSuccess) { // add the last locked item into the front of the locked // list so it behaves as a stack (FILO strategy) listLocked.Insert(0, key); // to prevent a deadlock don't wait afterwards waitNextMillis = 0; } else { if (i == 0) { // the very first key cannot be locked -- timeout return(null); } // unlock all we hold and try again foreach (var o in listLocked) { cache.Unlock(o); } listLocked.Clear(); // move the "offending" key to the top of the list // so next iteration we will attempt to lock it first listKeys.RemoveAt(i); listKeys.Insert(0, key); } } }while (!isSuccess); return(listLocked); }
/// <summary> /// Invoke the passed <see cref="IEntryProcessor"/> against the /// specified <see cref="IInvocableCacheEntry"/>. /// </summary> /// <remarks> /// The invocation is made thread safe by locking the corresponding key /// on the cache. /// </remarks> /// <param name="cache"> /// The <see cref="IConcurrentCache"/> that the /// <b>IEntryProcessor</b> works against. /// </param> /// <param name="entry"> /// The <b>IInvocableCacheEntry</b> to process; it is not required to /// exist within the cache. /// </param> /// <param name="agent"> /// The <b>IEntryProcessor</b> to use to process the specified key. /// </param> /// <returns> /// The result of the invocation as returned from the /// <b>IEntryProcessor</b>. /// </returns> public static object InvokeLocked(IConcurrentCache cache, IInvocableCacheEntry entry, IEntryProcessor agent) { var key = entry.Key; cache.Lock(key, -1); try { return(agent.Process(entry)); } finally { cache.Unlock(key); } }