コード例 #1
0
        /// <summary>
        /// Executes specified task and starts cooresponding callback necessary for cooperation.
        /// </summary>
        /// <param name="taskWithInformation">Task to be executed</param>
        private void RunTask(PrioritizedLimitedTask taskWithInformation)
        {
            lock (schedulingLocker)
            {
                executingTasks.TryAdd(taskWithInformation.PrioritizedLimitedTaskIdentifier, taskWithInformation);

                // If pending task was paused, than callback exist and does not need to be started again
                if (!taskWithInformation.CooperationMechanism.IsPaused && !taskWithInformation.CooperationMechanism.IsResumed)
                {
                    StartCallback(taskWithInformation,
                                  () => executingTasks.Remove(taskWithInformation.PrioritizedLimitedTaskIdentifier, out _),
                                  () => PauseCallback(taskWithInformation));
                }

                // Do not block a main thread.
                new Task(() =>
                {
                    if (taskWithInformation.CooperationMechanism.IsPaused)
                    {
                        taskWithInformation.CooperationMechanism.Resume();
                    }
                    else
                    {
                        TryExecuteTask(taskWithInformation);
                    }
                }).Start();
            }
        }
コード例 #2
0
        /// <summary>
        /// Using preemptive algorithm, runs tasks (number of tasks dependins on parallelism level).
        /// Deadlock avoidance is enabled.
        /// </summary>
        public override void RunScheduling()
        {
            lock (schedulingLocker)
                while (!pendingTasks.IsEmpty && executingTasks.Count < maxLevelOfParallelism)
                {
                    // Get task that is next for execution (task with highest priority)
                    PrioritizedLimitedTask taskWithInformation = GetNextTaskWithDeadlockAvoidance();
                    executingTasks.TryAdd(taskWithInformation.PrioritizedLimitedTaskIdentifier, taskWithInformation);

                    // If pending task was paused, than callback exist and does not need to be created again
                    if (!taskWithInformation.CooperationMechanism.IsPaused && !taskWithInformation.CooperationMechanism.IsResumed)
                    {
                        StartCallback(taskWithInformation,
                                      () => executingTasks.Remove(taskWithInformation.PrioritizedLimitedTaskIdentifier, out _),
                                      () => PauseCallback(taskWithInformation));
                    }

                    // Do not block a main thread.
                    new Task(() =>
                    {
                        if (taskWithInformation.CooperationMechanism.IsPaused)
                        {
                            taskWithInformation.CooperationMechanism.Resume();
                        }
                        else
                        {
                            TryExecuteTask(taskWithInformation);
                        }
                    }).Start();
                }
        }
コード例 #3
0
 /// <summary>
 /// Delays execution of a callback for specific amount of time.
 /// </summary>
 /// <param name="taskWithInformation">Task that contains information about that time.</param>
 private void PauseCallback(PrioritizedLimitedTask taskWithInformation)
 {
     do
     {
         if (taskWithInformation.CooperationMechanism.IsPaused || taskWithInformation.CooperationMechanism.IsResumed)
         {
             Task.Delay(taskWithInformation.CooperationMechanism.PausedFor).Wait();
         }
     }while (taskWithInformation.CooperationMechanism.IsPaused);
 }
コード例 #4
0
 /// <summary>
 /// If a task uses no shared resources, deadlock will be avoided. Otherwise,
 /// call is delegated to a manager that uses Banker's algorithm and decides whether deadlock can be avoided <see cref="IBankerAlgorithm"/>.
 /// </summary>
 private bool CanAvoidDeadlock(PrioritizedLimitedTask task)
 {
     lock (schedulingLocker)
     {
         RequestApproval approved = RequestApproval.Approved;
         if (task.UsesSharedResources())
         {
             approved = sharedResourceManager.AllocateResources(task.PrioritizedLimitedTaskIdentifier
                                                                , task.SharedResources);
         }
         return(approved == RequestApproval.Approved);
     }
 }
コード例 #5
0
 /// <summary>
 /// Starts (creates and schedules) task that is used to cooperatively cancels (and optionally pauses) user's task.
 /// Is user's task used resources, resources are released.
 /// This task is scheduled using default .NET scheduler.
 /// </summary>
 /// <param name="task">Corresponding user's task</param>
 /// <param name="controlNumberOfExecutionTasksAction">Responsible for decrementing number of currently running tasks</param>
 /// <param name="enablePauseAction">Responsible for pausing this callback for specific amount of time (optional)</param>
 protected void StartCallback(PrioritizedLimitedTask task, Action controlNumberOfExecutionTasksAction, Action enablePauseAction = null)
 => Task.Factory.StartNew(() =>
 {
     Task.Delay(task.DurationInMiliseconds).Wait();
     enablePauseAction?.Invoke();
     task.CooperationMechanism.Cancel();
     // Free shared resources
     if (task.UsesSharedResources())
     {
         sharedResourceManager.FreeResources(task.PrioritizedLimitedTaskIdentifier, task.SharedResources);
     }
     controlNumberOfExecutionTasksAction.Invoke();
     RunScheduling();
 }, CancellationToken.None, TaskCreationOptions.None, Default);
コード例 #6
0
        /// <summary>
        /// Using preemptive scheduling algorithm, runs task.
        /// </summary>
        public override void RunScheduling()
        {
            lock (schedulingLocker)
            {
                while (!pendingTasks.IsEmpty && currentlyRunningTasks < maxLevelOfParallelism)
                {
                    PrioritizedLimitedTask taskWithInformation = GetNextTaskWithDeadlockAvoidance();
                    StartCallback(taskWithInformation, () => Interlocked.Decrement(ref currentlyRunningTasks));
                    Interlocked.Increment(ref currentlyRunningTasks);

                    // Do not block a main thread
                    new Task(() => TryExecuteTask(taskWithInformation)).Start();
                }
            }
        }
コード例 #7
0
 /// <summary>
 /// Finds and returns a task that has all necessary resources and allocates those resources.
 /// It assumes that list is not empty, so a caller of this method needs to check that.
 /// </summary>
 protected PrioritizedLimitedTask GetNextTaskWithDeadlockAvoidance()
 {
     pendingTasks.TryDequeue(out PrioritizedLimitedTask taskWithInformation);
     if (taskWithInformation.UsesSharedResources())
     {
         RequestApproval approved = sharedResourceManager.AllocateResources(taskWithInformation.PrioritizedLimitedTaskIdentifier
                                                                            , taskWithInformation.SharedResources);
         if (approved == RequestApproval.Wait)
         {
             PrioritizedLimitedTask nextTask = GetNextTaskWithDeadlockAvoidance();
             pendingTasks.Enqueue(taskWithInformation);
             taskWithInformation = nextTask;
         }
     }
     return(taskWithInformation);
 }
コード例 #8
0
 /// <summary>
 /// This method simulates a context switch (pauses one task, and runs another) if there is a guarantee that deadlock won't happen.
 /// If a task does not get necessary resources, normal scheduling is called (no context switching and no interruption).
 /// </summary>
 /// <param name="taskForExecution">Task to be executed</param>
 /// <param name="taskToPause">Task to pause</param>
 private void RequestContextSwitch(PrioritizedLimitedTask taskForExecution, PrioritizedLimitedTask taskToPause)
 {
     lock (schedulingLocker)
         // TODO: Move
         if (executingTasks.Count >= maxLevelOfParallelism && CanAvoidDeadlock(taskForExecution))
         {
             executingTasks.Remove(taskToPause.PrioritizedLimitedTaskIdentifier, out _);
             taskToPause.CooperationMechanism.Pause(taskToPause.DurationInMiliseconds);
             pendingTasks.Enqueue(taskToPause);
             RunTask(taskForExecution);
         }
         else
         {
             SortPendingTasks();
             RunScheduling();
         }
 }
コード例 #9
0
        /// <summary>
        /// Schedules task based on a priority. If the task has a greater prirority than one of the currently running tasks,
        /// and if one of the currently running tasks allows cooperative context-switching, than context-switching will happen.
        /// </summary>
        /// <param name="task">Task to be scheduled (must extend <see cref="PrioritizedLimitedTask"/>),
        /// otherwise exception will be thrown</param>
        /// <exception cref="InvalidTaskException"></exception>
        protected override void QueueTask(Task task)
        {
            if (!(task is PrioritizedLimitedTask))
            {
                throw new InvalidTaskException();
            }

            pendingTasks.Enqueue(task as PrioritizedLimitedTask);
            Priority               priority         = (task as PrioritizedLimitedTask).Priority;
            PriorityComparer       priorityComparer = new PriorityComparer();
            PrioritizedLimitedTask taskToPause      = executingTasks.Values
                                                      .Where(x => x.CooperationMechanism.CanBePaused)
                                                      .Min();

            if (taskToPause != null && priority.CompareTo(taskToPause.Priority) > 0)
            {
                RequestContextSwitch(task as PrioritizedLimitedTask, taskToPause);
            }
            else
            {
                SortPendingTasks();
                RunScheduling();
            }
        }