{"id":4496,"date":"2014-03-30T11:53:39","date_gmt":"2014-03-30T11:53:39","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/prioritized-queues-in-task-parallel-library-collection-of-common-programming-errors\/"},"modified":"2014-03-30T11:53:39","modified_gmt":"2014-03-30T11:53:39","slug":"prioritized-queues-in-task-parallel-library-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/prioritized-queues-in-task-parallel-library-collection-of-common-programming-errors\/","title":{"rendered":"Prioritized queues in Task Parallel Library-Collection of common programming errors"},"content":{"rendered":"<p>So here is a rather naive concurrent implementation around a rather naive priority queue. The idea here is that there is a sorted set that holds onto pairs of both the real item and a priority, but is given a comparer that just compares the priority. The constructor takes a function that computes the priority for a given object.<\/p>\n<p>As for actual implementation, they&#8217;re not efficiently implemented, I just <code>lock<\/code> around everything. Creating more efficient implementations would prevent the use of <code>SortedSet<\/code> as a priority queue, and re-implementing one of those that can be effectively accessed concurrently is not going to be that easy.<\/p>\n<p>In order to change the priority of an item you&#8217;ll need to remove the item from the set and then add it again, and to find it without iterating the whole set you&#8217;d need to know the old priority as well as the new priority.<\/p>\n<pre><code>public class ConcurrentPriorityQueue : IProducerConsumerCollection\n{\n    private object key = new object();\n    private SortedSet set;\n\n    private Func prioritySelector;\n\n    public ConcurrentPriorityQueue(Func prioritySelector, IComparer comparer = null)\n    {\n        this.prioritySelector = prioritySelector;\n        set = new SortedSet(\n            new MyComparer(comparer ?? Comparer.Default));\n    }\n\n    private class MyComparer : IComparer\n    {\n        private IComparer comparer;\n        public MyComparer(IComparer comparer)\n        {\n            this.comparer = comparer;\n        }\n        public int Compare(Tuple first, Tuple second)\n        {\n            var returnValue = first.Item2.CompareTo(second.Item2);\n            if (returnValue == 0)\n                returnValue = comparer.Compare(first.Item1, second.Item1);\n            return returnValue;\n        }\n    }\n\n    public bool TryAdd(T item)\n    {\n        lock (key)\n        {\n            return set.Add(Tuple.Create(item, prioritySelector(item)));\n        }\n    }\n\n    public bool TryTake(out T item)\n    {\n        lock (key)\n        {\n            if (set.Count &gt; 0)\n            {\n                var first = set.First();\n                item = first.Item1;\n                return set.Remove(first);\n            }\n            else\n            {\n                item = default(T);\n                return false;\n            }\n        }\n    }\n\n    public bool ChangePriority(T item, int oldPriority, int newPriority)\n    {\n        lock (key)\n        {\n            if (set.Remove(Tuple.Create(item, oldPriority)))\n            {\n                return set.Add(Tuple.Create(item, newPriority));\n            }\n            else\n                return false;\n        }\n    }\n\n    public bool ChangePriority(T item)\n    {\n        lock (key)\n        {\n            var result = set.FirstOrDefault(pair =&gt; object.Equals(pair.Item1, item));\n\n            if (object.Equals(result.Item1, item))\n            {\n                return ChangePriority(item, result.Item2, prioritySelector(item));\n            }\n            else\n            {\n                return false;\n            }\n        }\n    }\n\n    public void CopyTo(T[] array, int index)\n    {\n        lock (key)\n        {\n            foreach (var item in set.Select(pair =&gt; pair.Item1))\n            {\n                array[index++] = item;\n            }\n        }\n    }\n\n    public T[] ToArray()\n    {\n        lock (key)\n        {\n            return set.Select(pair =&gt; pair.Item1).ToArray();\n        }\n    }\n\n    public IEnumerator GetEnumerator()\n    {\n        return ToArray().AsEnumerable().GetEnumerator();\n    }\n\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n\n    public void CopyTo(Array array, int index)\n    {\n        lock (key)\n        {\n            foreach (var item in set.Select(pair =&gt; pair.Item1))\n            {\n                array.SetValue(item, index++);\n            }\n        }\n    }\n\n    public int Count\n    {\n        get { lock (key) { return set.Count; } }\n    }\n\n    public bool IsSynchronized\n    {\n        get { return true; }\n    }\n\n    public object SyncRoot\n    {\n        get { return key; }\n    }\n}\n<\/code><\/pre>\n<p>Once you have an <code>IProducerConsumerCollection<\/code> instance, which the above object is, you can use it as the internal backing object of a <code>BlockingCollection<\/code> in order to have an easier to use user interface.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So here is a rather naive concurrent implementation around a rather naive priority queue. The idea here is that there is a sorted set that holds onto pairs of both the real item and a priority, but is given a comparer that just compares the priority. The constructor takes a function that computes the priority [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4496","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4496","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=4496"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4496\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=4496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=4496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=4496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}