Task scheduler
We assume that the hardware platform of the target embedded systems is a single processor with m identical cores, Core1, Core2, …, Corem. The task set V={v1, v2, …, vn} consists of n independent, non-pre-emptible tasks. A non-pre-emptible task cannot be pre-empted by another task during its execution, i.e., it runs to completion without being interrupted. Each task vi (i=1, 2, …, n) has four attributes: a unique task name vi, an execution time ci, a release time ri, and a deadline di (di>ri). All the execution times, the release times and deadlines are non-negative integers. You need to design a task scheduler and implement it in C. Your task scheduler uses EDF (Earliest Deadline First) heuristic to find a feasible schedule for a task set. A schedule of a task set specifies when each task starts and on which core it is executed. A feasible schedule is a schedule satisfying all the release time and deadline constraints.
The problem of finding a feasible schedule for this task scheduling problem is NP-complete. It is widely believed that an NP-complete problem has no polynomial-time algorithm. However, nobody can prove it.
First, we introduce two definitions: scheduling point and ready task.
- A scheduling point is a time point at which a task can be scheduled on a core, In other words, a scheduling point is either the release time or the completion time of a task.
- A task vi (i=1, 2, …, n) is ready at a time t if t≥ri holds.
The EDF scheduling heuristic works as follows:
- At each scheduling point ti (ti≤ti+1, i=1, 2, …), among all the ready tasks, find a task with the smallest deadline, and schedule it on an idle core such that its start time is minimized. Ties are broken arbitrarily.
Since this task scheduling problem is NP-complete, the EDF heuristic is not guaranteed to find a feasible schedule even if a feasible schedule exists.
Example One
Consider a set S1 of 6 independent tasks whose release times and deadlines are shown in Table 1. The target processor has two identical cores. A feasible schedule of the task set by using EDF scheduling strategy is shown in Figure 1.
Example Two
Consider a set S2 of 6 independent tasks whose release times and deadlines are shown in Table 2. The target processor has two identical cores. A schedule of the task set by using EDF scheduling strategy is shown in Figure 2. As we can see, in the schedule, v6 finishes at time 16 and thus misses its deadline. Therefore, the schedule is not feasible. However, a feasible schedule, as shown in Figure 3, does exist.
The TaskScheduler
function You need to write a task scheduler function named TaskScheduler. A prototype of TaskScheduler is shown as follows: int TaskScheduler(char *file1, char *file2, int m) {}; This function gets a task set from a file named file1, constructs a feasible schedule for the task set on a processor with m identical cores by using the EDF strategy, and writes the feasible schedule to file2. If a feasible schedule is found, it returns 1. Otherwise, it returns 0.
Both file1 and file2 are text files. file1 contains a set of independent tasks each of which has a name, an execution time, a release time and a deadline in that order. Task names, execution times, release times and the deadlines are a string of digits between 0 and 9. All the release times are non-negative integers, and all the execution times and the deadlines are natural numbers. The format of file1 is as follows:
v1 c1 r1 d1 v2 c2 r2 d2 … vn cn rn dn
Two adjacent attributes (task name, execution time, release time and deadline) are separated by one or more white space characters or a newline character. See attachment samplefile1.txt.
For simplicity, you may assume that all the task names in file1 are distinct. Therefore, you don’t need to check for duplicates.
The TaskScheduler function needs to handle the following possible cases properly when reading from file1 and writing to file2:
- file1 does not exist. In this case, print “file1 does not exist” and the program terminates.
- file2 already exists. In this case, overwrite the old file2.
- The task attributes (task name, execution time, release time and deadline) of file1 do not follow the formats as shown before. In this case, print “input error when reading the attribute of the task X” and the program terminates, where X is the name of the task with an incorrect attribute.
file2 has the following format:
v1 p1 t1 v2 p2 t2 … vn pn tn
where each vi (i=1, 2, …, n) is the task name, pi is the name of the core where vi is scheduled, and ti is the start time of the task vi in the schedule. In file2, all the tasks must be sorted in non-decreasing order of start times. See attachment samplefile2.txt.
Your task scheduler needs to use binomial heap-based priority queues.
Therefore, you also need to implement the following functions of a binomial heap-based priority queue:
- void Insert(BinomialHeap *T, int k, int n, int c, int r, int d). This function inserts a new task into a heap T, where k, n, c, r and d are the key, name, execution time, release time, and deadline of the task, respectively.
- HeapNode *RemoveMin(BinomialHeap *T). This function removes a task with the smallest key from the heap T and returns the node containing the task.
- int Min(BinomialHeap *T). This function returns the smallest key of all the tasks in the heap T without modifying the heap T.
The prototypes of all the above-mentioned function and some other basic functions are included in the template file MyTaskScheduler.c. In addition to the above functions, you may add your own helper functions and fields (variables) to the file MyTaskScheduler.c.
Note that you must implement a binomial heap-based priority queue. Any other priority queues are not acceptable.
Time complexity requirement
You need to include the time complexity analysis of each function as comments in your program. The time complexity of your scheduler is required to be no higher than O(n*log n), where n is the number of tasks (Hints: use three binomial heap-based priority queues, one priority queue with release times as keys, one priority queue with deadlines as keys and one priority queue for the scheduling points of all the cores). There is no specific requirement on space complexity. However, try your best to make your program space efficient.
When analysing the time complexity of your task scheduler, you can assume that the time complexity of each function (insertion, deletion, removeMin and merge) on a binomial heap is O(log n), where n is the number of tasks in the binomial heap.
Solution
Eg: samplefile4.txt:
t,e,r,d
1 4 0 10
2 6 0 15
3 2 2 6
4 2 2 8
5 2 2 8
6 5 1 13
7 5 2 13
8 5 5 18
9 3 5 19
10 2 5 19
11 4 6 24
12 5 6 24
Create three binomial heaps:
Then
- find the minimal node from Tc (avilable time):
core1 available time: 0 (minT) - find the minimal node from T (dealine time):
task name: 3, ready time 2 (rD), deadline 6 (dD) - find the minimal node from Tr: 1 (ready time)
task name 1, ready time = 0 (rR), deadline 10 (dR)
if minT < rD && rR < rD
remove from Tr, else remove from T.
the first task schedule is: 1 Core1 0
next: 2 Core2 0
next: 3 Core1 4
...
Finally, a feasible EDF schedule on 2 cores:
1 Core1 0 2 Core2 0 3 Core1 4 4 Core1 6 5 Core2 6 6 Core1 8 7 Core2 8 8 Core1 13 9 Core2 13 10 Core2 16 11 Core1 18 12 Core2 18
Attachment link: https://pan.baidu.com/s/14v33KqtTMxMkulotq-SbAA Password: pj5q
Reference link: Binomial heap
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。