public static void Initialize(int numWorkers = -1) { using var _ = new Timing("jobsvcinit"); lock (s_setupShutdownLock) { if (s_workers != null) { return; // already initialized } // set up a good amount of workers; but leave some room for main thread and misc other threads var hwThreads = Environment.ProcessorCount; // minimum 2 job workers; some may assume at least some concurrency if (numWorkers == -1) { numWorkers = (hwThreads <= 2) ? 2 : hwThreads - (1 + (hwThreads / 8)); } s_workers = new JobWorker[numWorkers]; for (int i = 0; i < numWorkers; i++) { s_workers[i] = new JobWorker(i); } } }
// execute one job on this thread (owned by worker) // return true if a job was found and executed internal static bool ExecuteAnyJob(JobWorker worker, JobCompletion requiredCompletion = null) { Job job; if (requiredCompletion != null) { if (StealJob(requiredCompletion, out job) == false) { return(false); } } else { if (s_instancesCount < 0 || PopAnyJob(out job) == false) { if (PopDelayed(out job) == false) { return(false); } } } // do job using (new Timing(job.Name)) { #if DEBUG if (worker != null) { worker.CurrentJob = job; } #endif // go go go job.Work(job.Argument); } var cmp = job.Completion; if (cmp != null) { cmp.IncrementCompleted(); } return(true); }
private void Run() { var tt = TimingThread.Instance; // init this thread // set thread local s_workerForThread = this; int numTotalWorkers = JobService.WorkersCount; for (; ;) { if (m_state == JobWorkerState.Shutdown) { TimingThread.Instance.InternalFlush(); return; // done } if (m_state == JobWorkerState.TimingFlushTriggered) { TimingThread.Instance.InternalFlush(); } if (JobService.ExecuteAnyJob(this)) { continue; } // wait for a job to be queued (may give false positives but...) int numIdle = Interlocked.Increment(ref JobService.m_idleWorkers); if (numIdle < numTotalWorkers) // at least one worker should always be awake { JobService.JobWait.WaitOne(); } numIdle = Interlocked.Decrement(ref JobService.m_idleWorkers); } }