<< Previous | Index | Next >> | |
|
A task is an ordered list of operations to perform. In a multitasking environment, more than one task (each representing a sequence of operations) can appear to execute in parallel. In reality, a single processor can only execute one instruction at a time. If an application has multiple tasks to perform, multitasking software can usually take advantage of natural delays in each task to increase the overall performance of the system. Each task can do some of its work while the other tasks are waiting for an event, or for something to do. In this way, the tasks execute almost in parallel.
There are two types of multitasking available for developing applications in Dynamic C: preemptive and cooperative. In a cooperative multitasking environment, each well-behaved task voluntarily gives up control when it is waiting, allowing other tasks to execute. Dynamic C has language extensions, costatements and cofunctions, to support cooperative multitasking. Preemptive multitasking is supported by the slice statement, which allows a computation to be divided into small slices of a few milliseconds each, and by the µC/OS-II real-time kernel.
5.1 Cooperative Multitasking
In the absence of a preemptive multitasking kernel or operating system, a programmer given a real-time programming problem that involves running separate tasks on different time scales will often come up with a solution that can be described as a big loop driving state machines.
This means that the program consists of a large, endless loop--a big loop. Within the loop, tasks are accomplished by small fragments of a program that cycle through a series of states. The state is typically encoded as numerical values in C variables.
State machines can become quite complicated, involving a large number of state variables and a large number of states. The advantage of the state machine is that it avoids busy waiting, which is waiting in a loop until a condition is satisfied. In this way, one big loop can service a large number of state machines, each performing its own task, and no one is busy waiting.
The cooperative multitasking language extensions added to Dynamic C use the big loop and state machine concept, but C code is used to implement the state machine rather than C variables. The state of a task is remembered by a statement pointer that records the place where execution of the block of statements has been paused to wait for an event.
To multitask using Dynamic C language extensions, most application programs will have some flavor of this simple structure:
main() {
int i;
while(1) { // endless loop for multitasking framework
costate { // task 1
. . . // body of costatement
}
costate { // task 2
... // body of costatement
}
}
}
5.2 A Real-Time Problem
The following sequence of events is common in real-time programming.
- Wait for a pushbutton to be pressed.
- Turn on the first device.
- Wait 60 seconds.
- Turn on the second device.
- Wait 60 seconds.
- Turn off both devices.
- Go back to the start.
The most rudimentary way to perform this function is to idle ("busy wait") in a tight loop at each of the steps where waiting is specified. But most of the computer time will used waiting for the task, leaving no execution time for other tasks.
5.2.1 Solving the Real-Time Problem with a State Machine
Here is what a state machine solution might look like.
If there are other tasks to be run, this control problem can be solved better by creating a loop that processes a number of tasks. Now each task can relinquish control when it is waiting, thereby allowing other tasks to proceed. Each task then does its work in the idle time of the other tasks.
5.3 Costatements
Costatements are Dynamic C extensions to the C language which simplify implementation of state machines. Costatements are cooperative because their execution can be voluntarily suspended and later resumed. The body of a costatement is an ordered list of operations to perform -- a task. Each costatement has its own statement pointer to keep track of which item on the list will be performed when the costatement is given a chance to run. As part of the startup initialization, the pointer is set to point to the first statement of the costatement.
The statement pointer is effectively a state variable for the costatement or cofunction. It specifies the statement where execution is to begin when the program execution thread hits the start of the costatement.
All costatements in the program, except those that use pointers as their names, are initialized when the function chain
_GLOBAL_INIT
is called._GLOBAL_INIT
is called automatically bypremain
beforemain
is called. Calling_GLOBAL_INIT
from an application program will cause reinitialization of anything that was initialized in the call made bypremain
.5.3.1 Solving the Real-Time Problem with Costatements
The Dynamic C costatement provides an easier way to control the tasks. It is relatively easy to add a task that checks for the use of an emergency stop button and then behaves accordingly.
The solution is elegant and simple. Note that the second costatement looks much like the original description of the problem. All the branching, nesting and variables within the task are hidden in the implementation of the costatement and its
waitfor
statements.5.3.2 Costatement Syntax
costate [ name [state] ] { [ statement | yield; | abort; | waitfor( expression ); ] . . .}
The keyword
costate
identifies the statements enclosed in the curly braces that follow as a costatement.
name
can be one of the following:
A valid C name not previously used. This results in the creation of a structure of type
CoData
of the same name.The name of a local or global
CoData
structure that has already been definedA pointer to an existing structure of type
CoData
- Costatements can be named or unnamed. If
name
is absent the compiler creates an "unnamed" structure of typeCoData
for the costatement.
state
can be one of the following:If
state
is absent, a named costatement is initialized in a pausedinit_on
condition. This means that the costatement will not execute untilCoBegin()
orCoResume()
is executed. It will then execute once and become inactive again.Unnamed costatements are
always_on
. You cannot specifyinit_on
without specifyingname
.5.3.3 Control Statements
waitfor
( expression );
- The keyword
waitfor
indicates a specialwaitfor
statement and not a function call. The expression is computed each timewaitfor
is executed. If true (non-zero), execution proceeds to the next statement, otherwise a jump is made to the closing brace of the costatement or cofunction, with the statement pointer continuing to point to thewaitfor
statement. Any valid C function that returns a value can be used in awaitfor
statement.
yield
- The yield statement makes an unconditional exit from a costatement or a cofunction. Execution continues at the statement following
yield
the next time the costatement or cofunction is encountered.
abort
- The abort statement causes the costatement or cofunction to terminate execution. If a costatement is
always_on
, the next time the program reaches it, it will restart from the top. If the costatement is notalways_on
, it becomes inactive and will not execute again until turned on by some other software.A costatement can have as many C statements, including
abort
,yield
, andwaitfor
statements, as needed. Costatements can be nested.5.4 Advanced Costatement Topics
Each costatement has a structure of type
CoData
. This structure contains state and timing information. It also contains the address inside the costatement that will execute the next time the program thread reaches the costatement. A value of zero in the address location indicates the beginning of the costatement.5.4.1 The CoData Structure
typedef struct {
char CSState;
unsigned int lastlocADDR;
char lastlocCBR;
char ChkSum;
char firsttime;
union{
unsigned long ul;
struct {
unsigned int u1;
unsigned int u2;
} us;
} content;
char ChkSum2;
} CoData;5.4.2 CoData Fields
CSState
The
CSState
field contains two flags,STOPPED
andINIT
. The possible flag values and their meaning are in the table below.The function
isCoDone()
returns true (1) if both theSTOPPED
andINIT
flags are set.The function
isCoRunning()
returns true (1) if theSTOPPED
flag is not set.The
CSState
field applies only if the costatement has a name TheCSState
flag has no meaning for unnamed costatements or cofunctions.Last Location
The two fields
lastlocADDR
andlastlocCBR
represent the 24-bit address of the location at which to resume execution of the costatement. If lastlocADDR
is zero (as it is when initialized), the costatement executes from the beginning, subject to theCSState
flag. IflastlocADDR
is nonzero, the costatement resumes at the 24-bit address represented bylastlocADDR
andlastlocCBR
.These fields are zeroed whenever one of the following is true:
the
CoData
structure is initialized by a call to _GLOBAL_INIT
,CoBegin
orCoReset
the costatement is executed to completion
the costatement is aborted.
Check Sum
The
ChkSum
field is a one-byte check sum of the address. (It is the exclusive-or result of the bytes inlastlocADDR
andlastlocCBR
.) IfChkSum
is not consistent with the address, the program will generate a run-time error and reset. The check sum is maintained automatically. It is initialized by_GLOBAL_INIT
,CoBegin
andCoReset
.First Time
The
firsttime
field is a flag that is used by awaitfor
, orwaitfordone
statement. It is set to 1 before the statement is evaluated the first time. This aids in calculating elapsed time for the functionsDelayMs
,DelaySec
,DelayTicks
,IntervalTick
,IntervalMs
, andIntervalSec
.Content
The
content
field (a union) is used by the costatement or cofunction delay routines to store a delay count.Check Sum 2
The
ChkSum2
field is currently unused.5.4.3 Pointer to CoData Structure
To obtain a pointer to a named costatement's CoData structure, do the following:
5.4.4 Functions for Use With Named Costatements
For detailed function descriptions, please see the Dynamic C Function Reference Manual or select Function Lookup/Insert from Dynamic C's Help menu (keyboard shortcut is <Ctrl-H>).
All of these functions are in
COSTATE.LIB
. Each one takes a pointer to aCoData
struct as its only parameter.
isCoDone
int isCoDone(CoData* p);
- This function returns true if the costatement pointed to by
p
has completed.
isCoRunning
int isCoRunning(CoData* p);
- This function returns true if the costatement pointed to by
p
will run if given a continuation call.
CoBegin
void CoBegin(CoData* p);
- This function initializes a costatement's
CoData
structure so that the costatement will be executed next time it is encountered.
CoPause
void CoPause(CoData* p);
- This function will change
CoData
so that the associated costatement is paused. When a costatement is called in this state it does an implicit yield until it is released by a call fromCoResume
orCoBegin
.
CoReset
void CoReset(CoData* p);
- This function initializes a costatement's CoData structure so that the costatement will not be executed the next time it is encountered (unless the costatement is declared
always_on.
)
CoResume
void CoResume(CoData* p);
- This function unpauses a paused costatement. The costatement will resume the next time it is called.
5.4.5 Firsttime Functions
In a function definition, the keyword
firsttime
causes the function to have an implicit first parameter: a pointer to the CoData structure of the costatement that calls it.The following
firsttime
functions are defined inCOSTATE.LIB.
For more information see the Dynamic C Function Reference Manual. These functions should be called inside awaitfor
statement because they do not yield while waiting for the desired time to elapse, but instead return 0 to indicate that the desired time has not yet elapsed.
DelayMs IntervalMs
DelaySec IntervalSec
DelayTicks IntervalTick
User-defined
firsttime
functions are allowed.5.4.6 Shared Global Variables
The variables
SEC_TIMER
,MS_TIMER
andTICK_TIMER
are shared, making them atomic when being updated. They are defined and initialized inVDRIVER.LIB
. They are updated by the periodic interrupt and are used byfirsttime
functions. They should not be modified by an application program. Costatements and cofunctions depend on these timer variables being valid for use inwaitfor
statements that call functions that read them. E.g. the following statement will accessSEC_TIMER
.waitfor(DelaySec(3));
5.5 Cofunctions
Cofunctions, like costatements, are used to implement cooperative multitasking. But, unlike costatements, they have a form similar to functions in that arguments can be passed to them and a value can be returned (but not a structure).
The default storage class for a cofunction's variables is
Instance
. Aninstance
variable behaves like astatic
variable, i.e., its value persists between function calls. Each instance of an Indexed Cofunction has its own set of instance variables. The compiler directive#class
does not change the default storage class for a cofunction's variables.All cofunctions in the program are initialized when the function chain
_GLOBAL_INIT
is called. This call is made bypremain
.5.5.1 Syntax
A cofunction definition is similar to the definition of a C function.
cofunc|scofunc type [name][[dim]]([type arg1, ..., type argN]) { [ statement | yield; | abort; | waitfor(expression);] ... }
cofunc, scofunc
- The keywords
cofunc
orscofunc
(a single-user cofunction) identify the statements enclosed in curly braces that follow as a cofunction.type
- Whichever keyword (
cofunc
orscofunc
)is used is followed by the data type returned (
void
,int
, etc.).name
- A
name
can be any valid C name not previously used. This results in the creation of a structure of typeCoData
of the same name.dim
- The cofunction
name
may be followed by a dimension if an indexed cofunction is being defined.cofunction arguments (arg1, . . ., argN)
- As with other Dynamic C functions, cofunction arguments are passed by value.
cofunction body
- A cofunction can have as many C statements, including
abort
,yield
,waitfor
, andwaitfordone
statements, as needed. Cofunctions can contain calls to other cofunctions.5.5.2 Calling Restrictions
You cannot assign a cofunction to a function pointer then call it via the pointer.
Cofunctions are called using a
waitfordone
statement. Cofunctions and thewaitfordone
statement may return an argument value as in the following example.
int j,k,x,y,z;
j = waitfordone x = Cofunc1;
k = waitfordone{ y=Cofunc2(...); z=Cofunc3(...); }
The keyword
waitfordone
(can be abbreviated to the keywordwfd
) must be inside a costatement or cofunction. Since a cofunction must be called from inside awfd
statement, ultimately awfd
statement must be inside a costatement.If only one cofunction is being called by
wfd
the curly braces are not needed.The
wfd
statement executes cofunctions andfirsttime
functions. When all the cofunctions andfirsttime
functions listed in thewfd
statement are complete (or one of them aborts), execution proceeds to the statement followingwfd
. Otherwise a jump is made to the ending brace of the costatement or cofunction where thewfd
statement appears and when the execution thread comes around again control is given back towfd
.In the example above,
x
,y
andz
must be set byreturn
statements inside the called cofunctions. Executing a return statement in a cofunction has the same effect as executing the end brace.In the example above, the variable
k
is a status variable that is set according to the following scheme. If no abort has taken place in any cofunction,k
is set to 1, 2, ..., n to indicate which cofunction inside the braces finished executing last. If an abort takes place,k
is set to -1, -2, ..., -n to indicate which cofunction caused the abort.5.5.2.1 Using the IX Register
Functions called from within a cofunction may use the IX register if they restore it before the cofunction is exited, which includes an exit via an incomplete
waitfordone
statement.In the case of an application that uses the #useix directive, the IX register will be corrupted when any stack-variable using function is called from within a cofunction, or if a stack-variable using function contains a call to a cofunction.
5.5.3 CoData Structure
The CoData structure discussed in Section 5.4.1 applies to cofunctions; each cofunction has an associated CoData structure.
5.5.4 Firsttime Functions
The
firsttime
functions discussed in Firsttime Functions can also be used inside cofunctions. They should be called inside awaitfor
statement. If you call these functions from inside awfd
statement, no compiler error is generated, but, since these delay functions do not yield while waiting for the desired time to elapse, but instead return 0 to indicate that the desired time has not yet elapsed, thewfd
statement will consider a return value to be completion of thefirsttime
function and control will pass to the statement following thewfd
.5.5.5 Types of Cofunctions
There are three types of cofunctions: simple, indexed and single-user. Which one to use depends on the problem that is being solved. A single-user, indexed cofunction is not valid.
5.5.5.1 Simple Cofunction
A simple cofunction has only one instance and is similar to a regular function with a costate taking up most of the function's body.
5.5.5.2 Indexed Cofunction
An indexed cofunction allows the body of a cofunction to be called more than once with different parameters and local variables. The parameters and the local variable that are not declared static have a special lifetime that begins at a first time call of a cofunction instance and ends when the last curly brace of the cofunction is reached or when an
abort
orreturn
is encountered.The indexed cofunction call is a cross between an array access and a normal function call, where the array access selects the specific instance to be run.
Typically this type of cofunction is used in a situation where N identical units need to be controlled by the same algorithm. For example, a program to control the door latches in a building could use indexed cofunctions. The same cofunction code would read the key pad at each door, compare the passcode to the approved list, and operate the door latch. If there are 25 doors in the building, then the indexed cofunction would use an index ranging from 0 to 24 to keep track of which door is currently being tested. An indexed cofunction has an index similar to an array index.
waitfordone{ ICofunc[n](...); ICofunc2[m](...); }
The value between the square brackets must be positive and less than the maximum number of instances for that cofunction. There is no runtime checking on the instance selected, so, like arrays, the programmer is responsible for keeping this value in the proper range.
5.5.5.2.1 Indexed Cofunction Restrictions
Costatements are not supported inside indexed cofunctions. Single user cofunctions can not be indexed.
5.5.5.3 Single User Cofunction
Since cofunctions are executing in parallel, the same cofunction normally cannot be called at the same time from two places in the same big loop. For example, the following statement containing two simple cofunctions will generally cause a fatal error.
waitfordone{ cofunc_nameA(); cofunc_nameA();}
This is because the same cofunction is being called from the second location after it has already started, but not completed, execution for the call from the first location. The cofunction is a state machine and it has an internal statement pointer that cannot point to two statements at the same time.
Single-user cofunctions can be used instead. They can be called simultaneously because the second and additional callers are made to wait until the first call completes. The following statement, which contains two single-user cofunctions, is okay.
waitfordone( scofunc_nameA(); scofunc_nameA();}
loopinit()
This function should be called in the beginning of a program that uses single-user cofunctions. It initializes internal data structures that are used by
loophead().
loophead()
This function should be called within the "big loop" in your program. It is necessary for proper single-user cofunction abandonment handling.
Example
// echoes characters
main() {
int c;
serXopen(19200);
loopinit();
while (1) {
loophead();
wfd c = cof_serAgetc();
wfd cof_serAputc(c);
}
serAclose();
}5.5.6 Types of Cofunction Calls
A
wfd
statement makes one of three types of calls to a cofunction.5.5.6.1 First Time Call
A first time call happens when a
wfd
statement calls a cofunction for the first time in that statement. After the first time, only the originalwfd
statement can give this cofunction instance continuation calls until either the instance is complete or until the instance is given another first time call from a different statement.5.5.6.2 Continuation Call
A continuation call is when a cofunction that has previously yielded is given another chance to run by the enclosing
wfd
statement. These statements can only call the cofunction if it was the last statement to give the cofunction a first time call or a continuation call.5.5.6.3 Terminal Call
A terminal call ends with a cofunction returning to its
wfd
statement without yielding to another cofunction. This can happen when it reaches the end of the cofunction and does an implicit return, when the cofunction does an explicit return, or when the cofunction aborts.5.5.6.4 Lifetime of a Cofunction Instance
This stretches from a first time call until its terminal call or until its next first time call.
5.5.7 Special Code Blocks
The following special code blocks can appear inside a cofunction.
everytime
{
statements}
- This must be the first statement in the cofunction. It will be executed every time program execution passes to the cofunction no matter where the statement pointer is pointing. After the
everytime
statements are executed, control will pass to the statement pointed to by the cofunction's statement pointer.abandon { statements }
- This keyword applies to single-user cofunctions only and must be the first statement in the body of the cofunction. The statements inside the curly braces will be executed if the single-user cofunction is forcibly abandoned. A call to
loophead()
(defined inCOFUNC.LIB
) is necessary for abandon statements to execute.Example
SAMPLES/COFUNC/
COFABAND
.C
illustrates the use ofabandon
.In this example two tasks in
main
are requesting access toSCofTest
. The first request is honored and the second request is held. Whenloophead
notices that the first caller is not being called each time around the loop, it cancels the request, calls the abandonment code and allows the second caller in.5.5.8 Solving the Real-Time Problem with Cofunctions
Cofunctions, with their ability to receive arguments and return values, provide more flexibility and specificity than our previous solutions. Using cofunctions, new machines can be added with only trivial code changes. Making
buttonpushed()
a cofunction allows more specificity because the value returned can indicate a particular button in an array of buttons. Then that value can be passed as an argument to the cofunctionsturnondevice
andturnoffdevice
.5.6 Patterns of Cooperative Multitasking
Sometimes a task may be something that has a beginning and an end. For example, a cofunction to transmit a string of characters via the serial port begins when the cofunction is first called, and continues during successive calls as control cycles around the big loop. The end occurs after the last character has been sent and the
waitfordone
condition is satisified. This type of a call to a cofunctions might look like this:
waitfordone{ SendSerial("string of characters"); }
[ next statement ]
The next statement will execute after the last character is sent.
Some tasks may not have an end. They are endless loops. For example, a task to control a servo loop may run continuously to regulate the temperature in an oven. If there are a a number of tasks that need to run continuously, then they can be called using a single
waitfordone
statement as shown below.
costate {
waitfordone { Task1(); Task2(); Task3(); Task4(); }
[ to come here is an error ]
}
Each task will receive some execution time and, assuming none of the tasks is completed, they will continue to be called. If one of the cofunctions should abort, then the waitfordone statement will abort, and corrective action can be taken.
5.7 Timing Considerations
In most instances, costatements and cofunctions are grouped as periodically executed tasks. They can be part of a real-time task, which executes every n milliseconds as shown below using costatements.
If all goes well, the first costatement will be executed at the periodic rate. The second costatement will, however, be delayed by the first costatement. The third will be delayed by the second, and so on. The frequency of the routine and the time it takes to execute comprise the granularity of the routine.
If the routine executes every 25 milliseconds and the entire group of costatements executes in 5 to 10 milliseconds, then the granularity is 30 to 35 milliseconds. Therefore, the delay between the occurrence of a
waitfor
event and the statement following thewaitfor
can be as much as the granularity, 30 to 35 ms. The routine may also be interrupted by higher priority tasks or interrupt routines, increasing the variation in delay.The consequences of such variations in the time between steps depends on the program's objective. Suppose that the typical delay between an event and the controller's response to the event is 25 ms, but under unusual circumstances the delay may reach 50 ms. An occasional slow response may have no consequences whatsoever. If a delay is added between the steps of a process where the time scale is measured in seconds, then the result may be a very slight reduction in throughput.
If there is a delay between sensing a defective product on a moving belt and activating the reject solenoid that pushes the object into the reject bin, the delay could be serious. If a critical delay cannot exceed 40 ms, then a system will sometimes fail if its worst-case delay is 50 ms.
5.7.1 waitfor Accuracy Limits
If an idle loop is used to implement a delay, the processor continues to execute statements almost immediately (within nanoseconds) after the delay has expired. In other words, idle loops give precise delays. Such precision cannot be achieved with waitfor delays.
A particular application may not need very precise delay timing. Suppose the application requires a 60-second delay with only 100 ms of delay accuracy; that is, an actual delay of 60.1 seconds is considered acceptable. Then, if the processor guarantees to check the delay every 50 ms, the delay would be at most 60.05 seconds, and the accuracy requirement is satisfied.
5.8 Overview of Preemptive Multitasking
In a preemptive multitasking environment, tasks do not voluntarily relinquish control. Tasks are scheduled to run by priority level and/or by being given a certain amount of time.
There are two ways to accomplish preemptive multitasking using Dynamic C. The first way is µC/OS-II, a real-time, preemptive kernel that runs on the Rabbit microprocessor and is fully supported by Dynamic C. For more information see Chapter 18, "µC/OS-II." The other way is to use
slice
statements.5.9 Slice Statements
The slice statement, based on the costatement language construct, allows the programmer to run a block of code for a specific amount of time.
5.9.1 Syntax
slice ([context_buffer,] context_buffer_size, time_slice) [name]{[statement|yield;|abort;|waitfor(expression);]}
context_buffer_size
- This value must evaluate to a constant integer. The value specifies the number of bytes for the buffer
context_buffer
. It needs to be large enough for worst-case stack usage by the user program and interrupt routines.time_slice
- The amount of time in ticks for the slice to run. One tick = 1/1024 second.
name
- When defining a named
slice
statement, you supply a context buffer as the first argument. When you define an unnamedslice
statement, this structure is allocated by the compiler.[statement | yield; | abort; | waitfor(expression);]
- The body of a
slice
statement may contain:
Regular C statements
yield
statements to make an unconditional exit.
abort
statements to make an execution jump to the very end of the statement.
waitfor
statements to suspend progress of the slice statement pending some condition indicated by the expression.5.9.2 Usage
The
slice
statement can run both cooperatively and preemptively all in the same framework. A slice statements, like costatements and cofunctions, can suspend its execution with anabort
,yield
, orwaitfor
as with costatements and cofunctions, or with an implicityield
determined by thetime_slice
parameter that was passed to it.A routine called from the periodic interrupt forms the basis for scheduling slice statements. It counts down the ticks and changes the
slice
statement's context.5.9.3 Restrictions
Since a
slice
statement has its own stack, local auto variables and parameters cannot be accessed while in the context of aslice
statement. Any functions called from the slice statement function normally.Only one
slice
statement can be active at any time, which eliminates the possibility of nestingslice
statements or using aslice
statement inside a function that is either directly or indirectly called from aslice
statement. The only methods supported for leaving aslice
statement are completely executing the last statement in theslice
, or executing anabort
,yield
orwaitfor
statement.The
return
,continue
,break
, andgoto
statements are not supported.Slice statements cannot be used with µC/OS-II or
DCRTCP.LIB
.5.9.4 Slice Data Structure
Internally, the
slice
statement uses two structures to operate. When defining a namedslice
statement, you supply a context buffer as the first argument. When you define an unnamedslice
statement, this structure is allocated by the compiler. Internally, the context buffer is represented by theSliceBuffer
structure below.
struct SliceData {
int time_out;
void* my_sp;
void* caller_sp;
CoData codata;
}struct SliceBuffer {
SliceData slice_data;
char stack[]; // fills rest of the slice buffer
};
5.9.5 Slice Internals
When a
slice
statement is given control, it saves the current context and switches to a context associated with theslice
statement. After that, the driving force behind theslice
statement is the timer interrupt. Each time the timer interrupt is called, it checks to see if aslice
statement is active. If aslice
statement is active, the timer interrupt decrements thetime_out
field in theslice
'sSliceData
. When the field is decremented to zero, the timer interrupt saves theslice
statement's context into theSliceBuffer
and restores the previous context. Once the timer interrupt completes, the flow of control is passed to the statement directly following theslice
statement. A similar set of events takes place when theslice
statement does an explicityield
/abort
/waitfor
.5.9.5.1 Example 1
Two
slice
statements and a costatement will appear to run in parallel. Each block will run independently, but theslice
statement blocks will suspend their operation after 20 ticks forslice_a
and 40 ticks forslice_b
. Costate a will not release control until it either explicitly yields, aborts, or completes. In contrast,slice_a
will run for at most 20 ticks, thenslice_b
will begin running. Costate a will get its next opportunity to run about 60 ticks after it relinquishes control.
main () {
int x, y, z;
...
for (;;) {
costate a {
...
}
slice(500, 20) { // slice_a
...
}
slice(500, 40) { // slice_b
...
}
}
}
5.9.5.2 Example 2
This code guarantees that the first slice starts on
TICK_TIMER
evenly divisible by 80 and the second starts onTICK_TIMER
evenly divisible by 105.
main() {
for(;;) {
costate {
slice(500,20) { // slice_a
waitfor(IntervalTick(80));
...
}
slice(500,50) { // slice_b
waitfor(IntervalTick(105);
...
}
}
}
}
5.9.5.3 Example 3
This approach is more complicated, but will allow you to spend the idle time doing a low-priority background task.
5.10 Summary
Although multitasking may actually decrease processor throughput slightly, it is an important concept. A controller is often connected to more than one external device. A multitasking approach makes it possible to write a program controlling multiple devices without having to think about all the devices at the same time. In other words, multitasking is an easier way to think about the system.
| |
<< Previous | Index | Next >> | |
Z-World, Inc. www.zworld.com Phone: 1.530.757.3737 Fax: 1.530.757.3792 |
Rabbit Semiconductor www.rabbitsemiconductor.com Phone: 1.530.757.8400 Fax: 1.530.757.8402 |