/// <summary> /// Function adds to the list of TaskRequests a TaskProxy will /// wait on. /// </summary> /// <param name="req">The TaskRequest to wait on</param> /// <returns>The Guid (TaskID) associated with the request. /// This TaskID is used to query for results once the /// TaskProxy signals the client that all task requests have /// been serviced.</returns> /// <remarks>Note: The TaskRequest queued may or may not have set /// a notification callback, if one has been set the TaskProxy will /// REPLACE it with its own notification callback.</remarks> /// <exception cref="ArgumentNullException">Thrown if a null /// TaskRequest is added</exception> public Guid AddTaskRequest(TaskRequest req) { if (req == null) { throw new ArgumentNullException("TaskRequest is null"); } // Assign taskID if we have to if (req.TaskID == Guid.Empty) { req.TaskID = Guid.NewGuid(); } Guid taskID = req.TaskID; // Enqueue task lock (m_requestQ.SyncRoot) { if (m_status != enuTaskProxyStatus.AcceptingRequests) { throw new InvalidOperationException("Proxy is no longer accepting requests - Check TaskProxy status"); } // Link notify callback to TaskProxy // note use of = instead of += // single TaskProxy is sole subscriber // to this request being serviced req.NotifyCb = new TaskRequest.NotificationCallback(this.OnTPTaskComplete); m_requestQ.Enqueue(req); m_nTasksPending++; } return(taskID); }
public static void QueueTaskRequest(TaskRequest req) { lock (TPTask.requestQ.SyncRoot) { // Add request item to TPTask requestQ TPTask.requestQ.Enqueue(req); } }
/// <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()
/// <summary> /// Function queues a TaskRequest to the TaskPool /// </summary> /// <param name="req">The TaskRequest to queue</param> /// <returns>A Guid used as a TaskID - if the TaskPool is in the process of /// Shutting down then Guid.Empty is returned</returns> /// <exception cref="ArgumentNullException">Thrown if TaskRequest /// is null or not valid</exception> public static Guid QueueTask(TaskRequest req) { if (req == null || !req.IsValid) { throw new ArgumentNullException("TaskRequest is null or contains null valued callbacks"); } // If taskpool is shutting down then return Guid.Empty if (bShuttingDown) { return(Guid.Empty); } if (!bInitialized) { Initialize(); } Guid taskID = Guid.Empty; try { /*lock( TPTask.requestQ.SyncRoot ) * { * // Generate Guid - task id if none exists * if( req.TaskID == Guid.Empty ) * req.TaskID = Guid.NewGuid(); * * taskID = req.TaskID; * * // Add request item to TPTask requestQ * TPTask.requestQ.Enqueue( req ); * }// End-lock on TPTask.requestQ */ // Generate Guid - task id if none exists if (req.TaskID == Guid.Empty) { req.TaskID = Guid.NewGuid(); } taskID = req.TaskID; TPTask.QueueTaskRequest(req); TaskPool.workSignal.Signal(); // Tag taskID to notification callback lock (ClientNotification.SyncRoot) { if (taskID != Guid.Empty && req.NotifyCb != null) { ClientNotification.Add(taskID, req.NotifyCb); } } // End-lock on ClientNotification } catch (Exception /*e*/) {} // Return taskID to client return(taskID); }