// // Author: Carson Jones // Adapted from "Art of Multiprocessor Programming" by Herlihy and Shavit // CS6966 // using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace PriorityQueueHeap { public class FineGrainedHeap { private enum Status { EMPTY, AVAILABLE, BUSY }; private class HeapNode { public Status tag; public int score; public S item; public int owner; private Object myLock; public void Init(S myItem, int myScore) { item = myItem; score = myScore; tag = Status.BUSY; owner = Thread.CurrentThread.ManagedThreadId; } public HeapNode() { tag = Status.EMPTY; myLock = new Object(); } public bool AmOwner() { if (tag == Status.BUSY && Thread.CurrentThread.ManagedThreadId == owner) return true; return false; } private bool locked = false; public void Lock() { Monitor.Enter(myLock); locked = true; } public void Unlock() { locked = false; Monitor.Exit(myLock); } } private static int ROOT = 1; private static int NO_ONE = -1; private Object heapLock; int next; HeapNode[] heap; public FineGrainedHeap(int capacity) { heapLock = new Object(); next = ROOT; heap = new HeapNode[capacity + 1]; for (int i = 0; i < capacity + 1; i++) { heap[i] = new HeapNode(); } } private void Swap(int indexNode1, int indexNode2) { HeapNode temp = heap[indexNode1]; heap[indexNode1] = heap[indexNode2]; heap[indexNode2] = temp; } public void Add(T item, int score) { // Create a new heap node int child; lock (heapLock) { child = next++; heap[child].Lock(); heap[child].Init(item, score); } heap[child].Unlock(); // Percolate while (child > ROOT) { int parent = child / 2; heap[parent].Lock(); heap[child].Lock(); int oldChild = child; try { if (heap[parent].tag == Status.AVAILABLE && heap[child].AmOwner()) { if (heap[child].score < heap[parent].score) { Swap(child, parent); child = parent; } else { heap[child].tag = Status.AVAILABLE; heap[child].owner = NO_ONE; return; } } else if (!heap[child].AmOwner()) { child = parent; } } finally { heap[oldChild].Unlock(); heap[parent].Unlock(); } } if (child == ROOT) { heap[ROOT].Lock(); if (heap[ROOT].AmOwner()) { heap[ROOT].tag = Status.AVAILABLE; heap[child].owner = NO_ONE; } heap[ROOT].Unlock(); } } public T RemoveMin() { int bottom; lock (heapLock) { bottom = --next; heap[bottom].Lock(); heap[ROOT].Lock(); } T item = heap[ROOT].item; heap[ROOT].tag = Status.EMPTY; heap[ROOT].owner = NO_ONE; Swap(bottom, ROOT); heap[bottom].Unlock(); if (heap[ROOT].tag == Status.EMPTY) { heap[ROOT].Unlock(); return item; } int child = 0; int parent = ROOT; while (parent < heap.Length / 2) { int left = parent * 2; int right = (parent * 2) + 1; heap[left].Lock(); heap[right].Lock(); if (heap[left].tag == Status.EMPTY) { heap[right].Unlock(); heap[left].Unlock(); break; } else if (heap[right].tag == Status.EMPTY || heap[left].score < heap[right].score) { heap[right].Unlock(); child = left; } else { heap[left].Unlock(); child = right; } if (heap[child].score < heap[parent].score) { Swap(parent, child); heap[parent].Unlock(); parent = child; } else { heap[child].Unlock(); break; } } heap[parent].Unlock(); return item; } } }