// Worker threads come here to take items off the work queue. // Multiple threads loop around here taking items off the work queue and // processing them. When there are no more things to do, the threads // return which puts them back in the thread pool. private void DoWork(object x) { while (m_workItems.Count > 0) { DoLaterBase w = null; lock (m_workItems) { if (m_workItems.Count > 0) { w = m_workItems.Dequeue(); } } if (w != null) { try { if (!w.DoIt()) { // LogManager.Log.Log(LogLevel.DRENDERDETAIL, "{0}.DoLater: DoWork: DoEvenLater", m_queueName); DoItEvenLater(w); } } catch (Exception e) { LogManager.Log.Log(LogLevel.DBADERROR, "{0}.DoLater: DoWork: EXCEPTION: {1}", m_queueName, e); // we drop the work item in the belief that it will exception again next time } } } lock (m_workItems) { m_activeWorkProcessors--; // not sure if this is atomic } }
// A thread from the outside world calls in here to do some work on the queue // We process work items on the queue until the queue is empty or we reach 'maximumCost'. // Each queued item has a delay (a time in the future when it can be done) and a // cost. As the work items are done, the cost is added up. // This means the thread coming in can count on being here only a limited amount // of time. public void ProcessQueue(int maximumCost) { int totalCost = 0; int totalCounter = 100; int now = System.Environment.TickCount; DoLaterBase found = null; while ((totalCost < maximumCost) && (totalCounter > 0) && (m_workQueue.Count > 0)) { now = System.Environment.TickCount; found = null; lock (m_workQueue) { // find an entry in the list who's time has come foreach (DoLaterBase ww in m_workQueue) { if (ww.remainingWait < now) { found = ww; break; } } if (found != null) { // if found, remove from list m_workQueue.Remove(found); } } if (found == null) { // if nothing found, we're done break; } else { // try to do the operation totalCounter--; if (found.DoIt()) { // if it worked, count it as successful totalCost += found.cost; } else { // if it didn't work, requeue it for later ((OnDemandWorkQueue)found.containingClass).DoLaterRequeue(ref found); } } } }