예제 #1
0
파일: Scheduler.cs 프로젝트: yusharth/psi
        /// <summary>
        /// Attempts to execute the delegate immediately, on the calling thread, without scheduling.
        /// </summary>
        /// <param name="synchronizationObject">Synchronization object.</param>
        /// <param name="action">Action to execute.</param>
        /// <param name="startTime">Scheduled start time.</param>
        /// <param name="context">The scheduler context on which to execute the action.</param>
        /// <returns>Success flag.</returns>
        public bool TryExecute(SynchronizationLock synchronizationObject, Action action, DateTime startTime, SchedulerContext context)
        {
            if (this.forcedShutdownRequested || startTime > context.FinalizeTime)
            {
                return(true);
            }

            if (startTime > this.clock.GetCurrentTime() && this.delayFutureWorkitemsUntilDue)
            {
                return(false);
            }

            if (!this.isSchedulerThread.Value && !this.allowSchedulingOnExternalThreads)
            {
                // this thread is not ours, so return
                return(false);
            }

            // try to acquire a lock
            // however, if this thread already has the lock, we have to give up to keep the no-reentrancy guarantee
            if (!synchronizationObject.TryLock())
            {
                return(false);
            }

            // ExecuteAndRelease assumes that the context has already been entered, so we must explicitly
            // enter it here. The context will be exited just prior to returning from ExecuteAndRelease.
            context.Enter();
            this.ExecuteAndRelease(synchronizationObject, action, context);
            this.counters?.Increment(SchedulerCounters.ImmediateWorkitemsPerSecond);
            return(true);
        }
예제 #2
0
        // executes the delegate immediately, on the calling thread, without scheduling
        public bool TryExecute(SynchronizationLock synchronizationObject, Action action, DateTime startTime)
        {
            if (this.forcedShutdownRequested)
            {
                return(true);
            }

            if (startTime > this.clock.GetCurrentTime() && this.delayFutureWorkitemsUntilDue)
            {
                return(false);
            }

            if (!this.isSchedulerThread.Value && !this.allowSchedulingOnExternalThreads)
            {
                // this thread is not ours, so return
                return(false);
            }

            // try to acquire a lock
            // however, if this thread already has the lock, we have to give up to keep the no-reentrancy guarantee
            if (!TryGetExclusiveLock(synchronizationObject))
            {
                return(false);
            }

            this.ExecuteAndRelease(synchronizationObject, action);
            this.counters?.Increment(SchedulerCounters.ImmediateWorkitemsPerSecond);
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Enqueues a workitem and, if possible, kicks off a worker thread to pick it up.
        /// </summary>
        /// <param name="synchronizationObject">Synchronization object.</param>
        /// <param name="action">Action to execute.</param>
        /// <param name="startTime">Scheduled start time.</param>
        /// <param name="context">The scheduler context on which to schedule the action.</param>
        /// <param name="asContinuation">Flag whether to execute once current operation completes.</param>
        /// <param name="allowSchedulingPastFinalization">Allow scheduling past finalization time.</param>
        public void Schedule(SynchronizationLock synchronizationObject, Action action, DateTime startTime, SchedulerContext context, bool asContinuation = true, bool allowSchedulingPastFinalization = false)
        {
            if (synchronizationObject == null || action == null || context == null)
            {
                throw new ArgumentNullException();
            }

            // Enter the context to track this new work item. The context will be exited
            // only after the work item has been successfully executed (or dropped).
            context.Enter();
            this.Schedule(new WorkItem() { SyncLock = synchronizationObject, Callback = action, StartTime = startTime, SchedulerContext = context });
        }
예제 #4
0
 private void ExecuteAndRelease(SynchronizationLock synchronizationObject, Action action)
 {
     try
     {
         action();
         this.counters?.Increment(SchedulerCounters.WorkitemsPerSecond);
     }
     catch (Exception e) when(this.errorHandler(e))
     {
     }
     finally
     {
         ReleaseExclusiveLock(synchronizationObject);
     }
 }
예제 #5
0
        /// <summary>
        /// Attempts to execute the delegate immediately, on the calling thread, without scheduling.
        /// </summary>
        /// <typeparam name="T">Action argument type.</typeparam>
        /// <param name="synchronizationObject">Synchronization object.</param>
        /// <param name="action">Action to execute.</param>
        /// <param name="argument">Action argument.</param>
        /// <param name="startTime">Scheduled start time.</param>
        /// <param name="context">The scheduler context on which to execute the action.</param>
        /// <returns>Success flag.</returns>
        public bool TryExecute <T>(SynchronizationLock synchronizationObject, Action <T> action, T argument, DateTime startTime, SchedulerContext context)
        {
            if (this.forcedShutdownRequested || startTime > context.FinalizeTime)
            {
                return(true);
            }

            if (startTime > this.clock.GetCurrentTime() && this.delayFutureWorkitemsUntilDue)
            {
                return(false);
            }

            if (!this.isSchedulerThread.Value && !this.allowSchedulingOnExternalThreads)
            {
                // this thread is not ours, so return
                return(false);
            }

            // try to acquire a lock on the sync context
            // however, if this thread already has the lock, we have to give up to keep the no-reentrancy guarantee
            if (!synchronizationObject.TryLock())
            {
                return(false);
            }

            try
            {
                // Unlike ExecuteAndRelease, which assumes that the context has already been entered (e.g.
                // when the work item was first created), we need to explicitly enter the context prior to
                // running the action. The context will be exited in the finally clause.
                context.Enter();

                action(argument);
                this.counters?.Increment(SchedulerCounters.WorkitemsPerSecond);

                this.counters?.Increment(SchedulerCounters.ImmediateWorkitemsPerSecond);
            }
            catch (Exception e) when(this.errorHandler(e))
            {
            }
            finally
            {
                synchronizationObject.Release();
                context.Exit();
            }

            return(true);
        }
예제 #6
0
파일: Scheduler.cs 프로젝트: yusharth/psi
 private void ExecuteAndRelease(SynchronizationLock synchronizationObject, Action action, SchedulerContext context)
 {
     try
     {
         action();
         this.counters?.Increment(SchedulerCounters.WorkitemsPerSecond);
     }
     catch (Exception e) when(this.errorHandler(e))
     {
     }
     finally
     {
         synchronizationObject.Release();
         context.Exit();
     }
 }
예제 #7
0
        /// <summary>
        /// Attempts to execute the delegate immediately, on the calling thread, without scheduling.
        /// </summary>
        /// <typeparam name="T">Action argument type</typeparam>
        /// <param name="synchronizationObject">Synchronization object</param>
        /// <param name="action">Action to execute</param>
        /// <param name="argument">Action argument</param>
        /// <param name="startTime">Scheduled start time</param>
        /// <returns>Success flag</returns>
        public bool TryExecute <T>(SynchronizationLock synchronizationObject, Action <T> action, T argument, DateTime startTime)
        {
            if (this.forcedShutdownRequested || startTime > this.finalizeTime)
            {
                return(true);
            }

            if (startTime > this.clock.GetCurrentTime() && this.delayFutureWorkitemsUntilDue)
            {
                return(false);
            }

            if (!this.isSchedulerThread.Value && !this.allowSchedulingOnExternalThreads)
            {
                // this thread is not ours, so return
                return(false);
            }

            // try to acquire a lock on the sync context
            // however, if this thread already has the lock, we have to give up to keep the no-reentrancy guarantee
            if (!TryGetExclusiveLock(synchronizationObject))
            {
                return(false);
            }

            try
            {
                action(argument);
                this.counters?.Increment(SchedulerCounters.WorkitemsPerSecond);

                this.counters?.Increment(SchedulerCounters.ImmediateWorkitemsPerSecond);
            }
            catch (Exception e) when(this.errorHandler(e))
            {
            }
            finally
            {
                ReleaseExclusiveLock(synchronizationObject);
            }

            return(true);
        }
예제 #8
0
 public PriorityQueueNode(int id)
 {
     this.id         = id;
     this.simpleLock = new SynchronizationLock(this, false);
 }
예제 #9
0
파일: Scheduler.cs 프로젝트: yusharth/psi
 /// <summary>
 /// Allow further scheduling.
 /// </summary>
 /// <param name="synchronizationObject">Synchronization object.</param>
 public void Thaw(SynchronizationLock synchronizationObject)
 {
     synchronizationObject.Release();
 }
예제 #10
0
파일: Scheduler.cs 프로젝트: yusharth/psi
 /// <summary>
 /// Prevent further scheduling.
 /// </summary>
 /// <param name="synchronizationObject">Synchronization object.</param>
 public void Freeze(SynchronizationLock synchronizationObject)
 {
     synchronizationObject.Hold();
 }
예제 #11
0
 private static void ReleaseExclusiveLock(SynchronizationLock synchronizationObject)
 {
     synchronizationObject.Release();
 }
예제 #12
0
 private static bool TryGetExclusiveLock(SynchronizationLock syncLock)
 {
     return(syncLock.TryLock());
 }
예제 #13
0
        // enqueues a workitem and, if possible, kicks off a worker thread to pick it up
        public void Schedule(SynchronizationLock synchronizationObject, Action action, DateTime startTime, bool asContinuation = true)
        {
            if (this.forcedShutdownRequested)
            {
                return;
            }

            if (synchronizationObject == null || action == null)
            {
                throw new ArgumentNullException();
            }

            WorkItem wi = new WorkItem()
            {
                SyncLock = synchronizationObject, Callback = action, StartTime = startTime
            };

            // if the workitem not yet due, add it to the future workitem queue
            if (startTime > this.clock.GetCurrentTime() && this.delayFutureWorkitemsUntilDue)
            {
                this.futureWorkitems.Enqueue(wi);
                this.futureAdded.Set();
                return;
            }

            // try to kick off another thread now, without going through the global queue
            if (TryGetExclusiveLock(synchronizationObject))
            {
                if (this.threadSemaphore.TryEnter())
                {
                    // there are threads available, which means the items in the global queue, if any, are locked
                    // start a thread to do the work
                    this.counters?.Increment(SchedulerCounters.ImmediateWorkitemsPerSecond);
                    ThreadPool.QueueUserWorkItem(this.Run, wi);
                    return;
                }

                ReleaseExclusiveLock(synchronizationObject);
            }

            // try to schedule on the local thread, to be executed once the current operation finishes, as long as the new workitem time is the same or less as the current one
            if (asContinuation && this.isSchedulerThread.Value && this.nextWorkitem.Value == null && wi.StartTime <= this.currentWorkitemTime.Value)
            {
                // we own the thread, so schedule the work in the local queue
                this.nextWorkitem.Value = wi;
                this.counters?.Increment(SchedulerCounters.LocalQueueCount);
                return;
            }

            // last resort, add the workitem to the global queue
            this.globalWorkitems.Enqueue(wi);

            // if a thread became available, it might have missed the workitem being enqueued, so retry to make sure
            if (this.threadSemaphore.TryEnter())
            {
                if (this.globalWorkitems.TryDequeue(out wi))
                {
                    this.counters?.Increment(SchedulerCounters.GlobalWorkitemsPerSecond);
                    ThreadPool.QueueUserWorkItem(this.Run, wi);
                }
                else
                {
                    this.threadSemaphore.Exit();
                }
            }
        }
예제 #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SchedulerContext"/> class.
 /// </summary>
 public SchedulerContext()
 {
     this.syncLock = new SynchronizationLock(this);
 }