2017-11-08 17 views
0

은 내가이 정말 큐의 사용 사례 아니라는 것을 알고,큐에서 표현

이제 난 단지 특정 객체를 큐에서 제거 할 상황이 Blocking QueueMarc Gravell's에 따라 차단 큐 클래스가 어디에와 대기열에서, 그러나 어떤 경우에는 이것이 좋은 확장이라고 생각합니다. 예를 들어 특정 네트워크 응답을 기다리는 것과 같습니다.

이 문제는 내가 특정 개체에 대기하고 차단하는 방법을 모른다 인

TryDequeueWhere(Func<T, bool> expression, out T value, int? waitTimeInMs = null) 

같은 것입니다.

+0

내가 BlockingQueue''대'BlockingCollection'를 사용하는 것이 좋습니다 것입니다. – mjwills

+0

'TryDequeueWhere'를 호출하면 어떻게 될까요? 일치하는 항목이 색인 5에 있다고 가정 해 봅시다. ** 정확히 ** 어떤 일이 발생합니까? 색인 6에 입장은 5까지 변화 할 것입니까 (등등)? – mjwills

+0

요소가 표현식과 일치하면 해당 위치에서 요소가 제거되므로 다음 요소가 오른쪽 위로 이동합니다. – Franki1986

답변

0

는 (감사 Pieter Witvoet를) codereview에 내 코드를 게시하고 다른 사용자의 제안에 의해 개선 후이 내 마지막 코드

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 

public class BlockingQueue<T>: IDisposable 
{ 

    /// <summary> The queue based on a list, to extract from position and remove at position. </summary> 
    private readonly List<QueueObject<T>> queue = new List<QueueObject<T>>(); 
    private bool _closing; 


    private class QueueObject<T> 
    { 
     //// <summary> Constructor. </summary> 
     /// <param name="timeStamp"> The time stamp when the object is enqueued. </param> 
     /// <param name="queuedObject"> The queued object. </param> 
     public QueueObject(DateTime timeStamp, T queuedObject) 
     { 
      TimeStamp = timeStamp; 
      QueuedObject = queuedObject; 
     } 

     /// <summary> Gets or sets the queued object. </summary> 
     /// <value> The queued object. </value> 
     public T QueuedObject { get; private set; } 

     /// <summary> Gets or sets timestamp, when the object was enqueued. </summary> 
     /// <value> The time stamp. </value> 
     public DateTime TimeStamp { get; private set; } 
    } 


    public void Enqueue(T item) 
    { 
     lock (queue) 
     { 
      // Add an object with current time to the queue 
      queue.Add(new QueueObject<T>(DateTime.Now, item)); 


      if (queue.Count >= 1) 
      { 
       // wake up any blocked dequeue 
       Monitor.PulseAll(queue); 
      } 
     } 
    } 

    /// <summary> Try dequeue an object that matches the passed expression. </summary> 
    /// <param name="expression"> The expression that an object has to match. </param> 
    /// <param name="value">  [out] The resulting object. </param> 
    /// <param name="waitTimeInMs"> (Optional) The time in ms to wait for the item to be returned. </param> 
    /// <returns> An object that matches the passed expression. </returns> 
    public bool TryDequeueWhere(Func<T, bool> expression, out T value, int? waitTimeInMs = null) 
    { 
     // Save the current time to later calculate a new timeout, if an object is enqueued and does not match the expression. 
     DateTime dequeueTime = DateTime.Now; 
     lock (queue) 
     { 
      while (!_closing) 
      { 
       if (waitTimeInMs == null) 
       { 
        while (queue.Count == 0) 
        { 
         if (_closing) 
         { 
          value = default(T); 
          return false; 
         } 
         Monitor.Wait(queue); 
        } 
       } 
       else 
       { 
        // Releases the lock on queue and blocks the current thread until it reacquires the lock. 
        // If the specified time-out interval elapses, the thread enters the ready queue. 
        if (!Monitor.Wait(queue, waitTimeInMs.Value)) 
        { 
         break; 
        } 
        try 
        { 
         // select the object by the passed expression 
         var queuedObjects = queue.Select(q => q.QueuedObject).ToList(); 
         // Convert the expression to a predicate to get the index of the item 
         Predicate<T> pred = expression.Invoke; 
         int indexOfQueuedObject = queuedObjects.FindIndex(pred); 
         // if item is found, get it and remove it from the list 
         if (indexOfQueuedObject >= 0) 
         { 
          value = queuedObjects.FirstOrDefault(expression); 
          queue.RemoveAt(indexOfQueuedObject); 
          return true; 
         } 
        } 
        catch (Exception) 
        { 
         break; 
        } 
        // If item was not found, calculate the remaining time and try again if time is not elapsed. 
        var elapsedTime = (DateTime.Now - dequeueTime).TotalMilliseconds; 
        if ((int) elapsedTime >= waitTimeInMs.Value) 
        { 
         break; 
        } 
        waitTimeInMs = waitTimeInMs.Value - (int) elapsedTime; 
       } 
      } 
     } 
     value = default(T); 
     return false; 
    } 

    /// <summary> Close the queue and let finish all waiting threads. </summary> 
    public void Close() 
    { 
     lock (queue) 
     { 
      _closing = true; 
      Monitor.PulseAll(queue); 
     } 
    } 

    /// <summary> 
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged 
    /// resources. 
    /// </summary> 
    public void Dispose() 
    { 
     Close(); 
    } 

}