/// <summary>
 /// Main worker run loop. Repeatedly gets tasks from queue and
 /// executes them, while coping with a number of issues:
 ///
 /// 1. We may start out with an initial task, in which case we
 /// don't need to get the first one. Otherwise, as long as pool is
 /// running, we get tasks from GetTask. If it returns null then the
 /// worker exits due to changed pool state or configuration
 /// parameters. Other exits result from exception throws in
 /// external code, in which case completedAbruptly holds, which
 /// usually leads ProcessWorkerExit to replace this thread.
 ///
 /// 2. Before running any task, the lock is acquired to prevent
 /// other pool interrupts while the task is executing, and
 /// ClearInterruptsForTaskRun called to ensure that unless pool is
 /// stopping, this thread does not have its interrupt set.
 ///
 /// 3. Each task run is preceded by a call to BeforeExecute, which
 /// might throw an exception, in which case we cause thread to die
 /// (breaking loop with completedAbruptly true) without processing
 /// the task.
 ///
 /// 4. Assuming BeforeExecute completes normally, we run the task,
 /// gathering any of its thrown exceptions to send to
 /// AfterExecute. We separately handle RuntimeException, Error
 /// (both of which the specs guarantee that we trap) and arbitrary
 /// Throwables. Because we cannot rethrow Throwables within
 /// Runnable.run, we wrap them within Errors on the way out (to the
 /// thread's UncaughtExceptionHandler). Any thrown exception also
 /// conservatively causes thread to die.
 ///
 /// 5. After task.run completes, we call AfterExecute, which may
 /// also throw an exception, which will also cause thread to
 /// die. According to JLS Sec 14.20, this exception is the one that
 /// will be in effect even if task.run throws.
 ///
 /// The net effect of the exception mechanics is that AfterExecute
 /// and the thread's UncaughtExceptionHandler have as accurate
 /// information as we can provide about any problems encountered by
 /// user code.
 /// <param name="worker">the worker to run</param>
 /// </summary>
 private void RunWorker(Worker worker)
 {
     var task = worker.FirstTask;
     worker.FirstTask = null;
     var completedAbruptly = true;
     try
     {
         while (task != null || (task = GetTask()) != null)
         {
             worker.Lock();
             ClearInterruptsForTaskRun();
             try
             {
                 BeforeExecute(worker.Thread, task);
                 Exception thrown = null;
                 try
                 {
                     task.Run();
                 }
                 catch (Exception x)
                 {
                     thrown = x;
                     OnThreadException(task, x);
                 }
                 finally
                 {
                     AfterExecute(task, thrown);
                 }
             }
             finally
             {
                 task = null;
                 worker.CompletedTasks++;
                 worker.Unlock();
             }
         }
         completedAbruptly = false;
     }
     finally
     {
         ProcessWorkerExit(worker, completedAbruptly);
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Main worker run loop.  Repeatedly gets tasks from queue and
 /// executes them, while coping with a number of issues:
 ///
 /// 1. We may start out with an initial task, in which case we
 /// don't need to get the first one. Otherwise, as long as pool is
 /// running, we get tasks from getTask. If it returns null then the
 /// worker exits due to changed pool state or configuration
 /// parameters.  Other exits result from exception throws in
 /// external code, in which case completedAbruptly holds, which
 /// usually leads processWorkerExit to replace this thread.
 ///
 /// 2. Before running any task, the lock is acquired to prevent
 /// other pool interrupts while the task is executing, and
 /// clearInterruptsForTaskRun called to ensure that unless pool is
 /// stopping, this thread does not have its interrupt set.
 ///
 /// 3. Each task run is preceded by a call to beforeExecute, which
 /// might throw an exception, in which case we cause thread to die
 /// (breaking loop with completedAbruptly true) without processing
 /// the task.
 ///
 /// 4. Assuming beforeExecute completes normally, we run the task,
 /// gathering any of its thrown exceptions to send to
 /// afterExecute. We separately handle RuntimeException, Error
 /// (both of which the specs guarantee that we trap) and arbitrary
 /// Throwables.  Because we cannot rethrow Throwables within
 /// Runnable.run, we wrap them within Errors on the way out (to the
 /// thread's UncaughtExceptionHandler).  Any thrown exception also
 /// conservatively causes thread to die.
 ///
 /// 5. After task.run completes, we call afterExecute, which may
 /// also throw an exception, which will also cause thread to
 /// die. According to JLS Sec 14.20, this exception is the one that
 /// will be in effect even if task.run throws.
 ///
 /// The net effect of the exception mechanics is that afterExecute
 /// and the thread's UncaughtExceptionHandler have as accurate
 /// information as we can provide about any problems encountered by
 /// user code.
 ///
 /// <param name="worker">the worker to run</param>
 /// </summary>
 protected void runWorker(Worker worker)
 {
     IRunnable task = worker.FirstTask;
     worker.FirstTask = null;
     bool completedAbruptly = true;
     try
     {
         while (task != null || (task = getTask()) != null)
         {
             worker.Lock();
             clearInterruptsForTaskRun();
             try
             {
                 beforeExecute(worker.Thread, task);
                 Exception thrown = null;
                 try
                 {
                     task.Run();
                 }
                 catch (Exception x)
                 {
                     thrown = x;
                     throw;
                 }
                 finally
                 {
                     afterExecute(task, thrown);
                 }
             }
             finally
             {
                 task = null;
                 worker.CompletedTasks++;
                 worker.Unlock();
             }
         }
         completedAbruptly = false;
     }
     finally
     {
         processWorkerExit(worker, completedAbruptly);
     }
 }