public static void Release(JobCompletion completion) { lock (s_free) { s_free.Add(completion); } }
/// <summary> /// Enqueue a list of actions to be performed concurrently; calls continuation(continuationArgument) when all completed /// </summary> public static void ForEachAction(string name, ReadOnlySpan <Action <object> > works, object argument, Action <object> continuation, object continuationArgument) { CoreException.Assert(s_workers != null, "JobService not initialized"); int numJobs = works.Length; if (numJobs == 0) { return; } if (numJobs == 1) { lock (s_instances) EnqueueInternal(name, works[0], argument); return; } var completion = JobCompletion.Acquire(); completion.ContinuationAtCount = numJobs; completion.Continuation = continuation; completion.ContinuationArgument = continuationArgument; #if DEBUG completion.ContinuationName = name + "Contd"; #endif lock (s_instances) { foreach (var work in works) { EnqueueInternal(name, work, argument, completion); } } }
public void WaitAndRelease(int completionCount) { CoreException.Assert(Continuation == null, "Can't use WaitAndRelease while also using a continuation"); for (; ;) { var comp = Volatile.Read(ref m_numCompleted); if (comp >= completionCount) { break; } Thread.Sleep(0); } JobCompletion.Release(this); }
/// <summary> /// Slower than pop; will try to steal ONLY jobs with a certain completion /// </summary> private static bool StealJob(JobCompletion completion, out Job job) { lock (s_instances) { int cnt = s_instancesCount; if (cnt <= 0) { job = default; return(false); } var idx = s_nextInstance; for (int i = 0; i < cnt; i++) { ref readonly var test = ref s_instances[idx];
internal void IncrementCompleted() { int cac = ContinuationAtCount; var numCompleted = Interlocked.Increment(ref m_numCompleted); if (numCompleted == cac && Continuation != null) { using (new Timing(ContinuationName == null ? "continuation" : ContinuationName)) { var post = Continuation; var postArg = ContinuationArgument; JobCompletion.Release(this); post(postArg); } } }
// 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); }
/// <summary> /// Enqueue work to be called once per argument in list; blocks until all completed /// </summary> public static void ForEachArgumentBlock <TArg>(string name, Action <object> work, ReadOnlySpan <TArg> arguments) { CoreException.Assert(s_workers != null, "JobService not initialized"); if (arguments.Length == 0) { return; } if (arguments.Length == 1) { work(arguments[0]); return; } int numJobs = arguments.Length - 1; var completion = JobCompletion.Acquire(); lock (s_instances) { foreach (var argument in arguments.Slice(1)) { EnqueueInternal(name, work, argument, completion); } } // run one time on this thread using (new Timing(name)) work(arguments[0]); // then, try to steal relevant jobs if possible // am I running within a job? try fetching the JobWorker for this thread var localWorker = JobWorker.WorkerForThread; while (JobService.ExecuteAnyJob(localWorker, completion)) { ; } completion.WaitAndRelease(numJobs); }
/// <summary> /// Enqueue a list of actions to be performed concurrently; calls continuation(continuationArgument) when all completed /// </summary> public static void ForEachActionBlock(string name, ReadOnlySpan <Action <object> > works, object argument) { CoreException.Assert(s_workers != null, "JobService not initialized"); if (works.Length == 0) { return; } if (works.Length == 1) { works[0](argument); return; } int numJobs = works.Length - 1; var completion = JobCompletion.Acquire(); lock (s_instances) { foreach (var work in works.Slice(1)) { EnqueueInternal(name, work, argument, completion); } } // run one time on this thread using (new Timing(name)) works[0](argument); // then, try to steal relevant jobs if possible while (JobService.ExecuteAnyJob(null, completion)) { ; } completion.WaitAndRelease(numJobs); }
internal static void EnqueueInternal(string name, Action <object> work, object argument, JobCompletion completion = null) { #if DEBUG CoreException.Assert(Monitor.IsEntered(s_instances)); #endif int idx = (s_nextInstance + s_instancesCount) & k_instancesMask; ref var job = ref s_instances[idx];