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);
 }
Exemple #4
0
        /// <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);
                }
            }
        }
Exemple #6
0
        // 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);
        }
Exemple #7
0
        /// <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);
        }
Exemple #9
0
        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];