/// <summary> /// Procedure represents the notification callback provided by the /// TaskProxy. This callback is invoked whenever a task the TaskProxy /// is waiting on has been serviced by the TaskPool. When all the tasks the /// proxy is waiting on have been serviced it will signal external clients /// using the condition variable reference passed from the client at /// TaskProxy construction. /// </summary> /// <param name="tceArg"></param> private void OnTPTaskComplete(TPTaskCompleteEventArgs tceArg) { lock (m_results.SyncRoot) { // Index results by TaskID m_results.Add(tceArg.TaskID, tceArg); m_nTasksPending--; if (m_nTasksPending == 0) { // Indicate results are ready by changing state m_status = enuTaskProxyStatus.ResultsReady; // Signal to any waiting client m_condition.Set(); } } }
/// <summary> /// TaskPool subscribes to the TPTaskComplete event. When a TPTask /// thread is finished servicing a request, locate the /// subscription of the client that queued the request and /// notify them via the callback they provided as part of /// their subscription. /// <seealso cref="TPTask"/> /// <seealso cref="TPTaskCompleteEventArgs"/> /// </summary> /// <param name="tceArg">TPTask completion event arguement</param> private static void OnTPTaskComplete(TPTaskCompleteEventArgs tceArg) { try { lock (ClientNotification.SyncRoot) { if (ClientNotification.ContainsKey(tceArg.TaskID)) { TaskRequest.NotificationCallback objNotify = (TaskRequest.NotificationCallback)ClientNotification[tceArg.TaskID]; if (objNotify != null) { // Notifiy specific client objNotify(tceArg); // Remove subscription ClientNotification.Remove(tceArg.TaskID); } } } } catch (Exception /*e*/) {} }
/// <summary> /// Procedure enforces the leader-followers behavior of TPTask threads /// </summary> /// <remarks></remarks> public void Service() { // Every thread that comes thru here ups the thread count Interlocked.Increment(ref nNumTasks); while (true) { // Begin critical section lock (this) { Console.WriteLine("Checking for leader"); // While a leader has been selected...wait around while (bLeaderAvailable) { Console.WriteLine("Waiting to be leader"); m_leaderSignal.WaitOnSignal(); Console.WriteLine("Received leader signal"); } // Assert self as leader before leaving critical section bLeaderAvailable = true; // Leave critical section Console.WriteLine("Leaving as leader"); } // Only one thread active at this point Console.WriteLine("Waiting on work"); // waiting on work m_workSignal.WaitOnSignal(); Console.WriteLine("Got work"); bool bExitLoop = false; // Nothing else to do so this thread can exit or be recycled if (requestQ.Count == 0) { // No work to do so let other threads (next leader) wait on work m_workSignal.Reset(); bExitLoop = true; } // Begin critical section lock (this) { // Signal self is no longer the leader bLeaderAvailable = false; // Signal a follower to become the new leader m_leaderSignal.Signal(); // Leave critical section } if (bExitLoop) { // If this task is not marked as recyclable // then it must exit if no requests are // pending if (!m_bRecycleTask) { // Thread on its way out so decrease thread count Interlocked.Decrement(ref nNumTasks); break; } } else { try { // Dequeue Service request TaskRequest req = (TaskRequest)requestQ.Dequeue(); // Set taskID this.TaskID = req.TaskID; // Execute Callback object objRes = req.TaskCb(req.Context); // If any one subscribed, then fire LFTaskDone event if (TPTaskComplete != null) { TPTaskCompleteEventArgs tceArg = new TPTaskCompleteEventArgs(); tceArg.TaskID = req.TaskID; tceArg.Result = objRes; TPTaskComplete(tceArg); } } catch (Exception e) // Catch any exceptions thrown { // If any one subscribed, then fire LFTaskFailed event if (TPTaskComplete != null) { TPTaskCompleteEventArgs tceArg = new TPTaskCompleteEventArgs(); tceArg.TaskID = this.TaskID; // Signal that we had errors so that // clients can check the // ExceptionMessage property tceArg.HasErrors = true; tceArg.Result = e.Message; TPTaskComplete(tceArg); } } finally { // Reset task ID this.TaskID = Guid.Empty; } } } // End-while(true) } // End-Method Service()