使用where表达式从队列出队 [英] Dequeue from Queue with where expression

查看:160
本文介绍了使用where表达式从队列出队的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于 Marc Gravell的 现在,我遇到了只想让某个对象出队的情况,我知道这实际上并不是队列的用例,但是在某些情况下,我认为这是一个很好的扩展,例如等待某个网络答案

Now I have situations where I want to dequeue only a certain object, I know this is not really the use case of a queue, but in some cases I think this is a good extension, for example waiting for a certain network answer.

这类似于

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

问题是我不知道如何等待和阻止某个对象.

The problem is I don't know how to wait and block for a certain object.

推荐答案

codereview 上发布我的代码后,由其他用户改进建议(感谢 Pieter Witvoet ),这是我的最终代码

After posting my code on codereview and improving by other users suggestions (thanks Pieter Witvoet) this is my final code

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();
    }

}

这篇关于使用where表达式从队列出队的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆