Mail Archives: djgpp/1993/10/31/18:24:26
> Is there any document for the task switcher (aetsk101.zip)
> somewhere? I realy like to use it, but don't know C++ and can't
> figure out what the code is doing. Any help in this one would be
> *greatly* appreciated.
Hi, 'ae' here. No, there really isn't a document for that beast. I can
give you the basic idea, though. I've been thinking about rewriting
some parts of that thing (I don't like the way the CPipes work, but I
don't know how to do it any better ... yet). If I do, I'll probably
produce a manual of sorts. I'm leaning to TeX format 'cause it's
probably the most portable; if I don't use TeX, it'll be Word for
Wastebaskets.
In the meantime, here's the basics of it (I'm not going to try and
explain C++ - that is left as a very worthwhile exercise for the reader -
but I will explain the practical use of the library):
First, everything is based on semaphores. If you don't know what a
semaphore is, well, .... it's an access control device. Basically, it
is a counter. It usually starts at 0 or 1. Let's look at something
simple: I have a printer device, and two tasks in my current process
can print. Now, we can't have them both writing indiscriminately or
else, as they say, hijinks ensue. So, a semaphore is used to control
who "owns" the printer. Now, C++ lets me overload operators, so I
might have something like:
Sema lpsema(1); // printer semaphore, init to 1 (printer is available)
void print1()
{
lpsema--; // decrement sema, waiting for it to become > 0
// if it isn't already (it would be < 1 if another
// task has already taken the printer)
// can also say: lpsema.wait();
PrintMyStuff();
lpsema++; // I'm done, so increment it again (this will wake
// up anybody else who has done a wait)
// can also say: lpsema.signal();
}
Now let's say I wanted to wait for the printer for a maximum of five
minutes and then give up if I can't have it:
void print2()
{
if (!lpsema.wait(5l * 60l * 1000l)) {
TellUser("Somebody's hogging the printer! Sorry!");
return;
}
PrintMyStuff();
lpsema.signal(); // for consistency's sake, I use the call
// sema.signal() when I previously did a
// sema.wait(), and I use sema++ when I
// previously did a sema--.
}
Now we get the idea of how to synchronize things between tasks. So,
what's a task? It's an entity that executes until it blocks waiting
on something (that something is ALWAYS a semaphore, even though it
may not look like it). A task has its own stack. It can have its own
variables, by defining them in the derived task class. There is no
limit to how many instances of a given task may be running (other than
core, of course). A task can just give up control, too, by calling
TaskSuspend(). This is useful for a low-priority background task. A
task does not ever get preempted; it must voluntarily relenquish the
CPU, either by waiting on something or because it is feeling
altruistic.
Let's look at a simple example, using the provided task to read the
keyboard.
#include "task.h"
#include "keybdtsk.h"
class Echo: public Task {
public:
Echo() : Task("Echo")
{ }
void TaskMain();
};
// this defines a task called Echo; each task is derived from class
// Task and must define an member called TaskMain() - that's where
// execution starts
// define the main function for the Echo task
void Echo::TaskMain()
{
char c;
for (;;) {
KbdPipe.recv(c); // get a char
if (c == 0x1b) { // escape kills us
scheduler(0); // stop the world
}
putchar(c); // echo to stdout
}
}
// Now declare vars, and crank it up
Echo echo;
int main(void)
{
scheduler(); // start up the world
// if you type ESC, then the Echo task will terminate
// the task scheduler and you'll end up here.
return 0;
}
// end of simple example
Now to see how this works, look at keybdtsk.cpp (or .cc, I guess, for
GNU). The keyboard task polls the keyboard, putting characers on a
pipe called KbdPipe. The Echo task reads from the pipe, which blocks
until a character is available, then it writes it out.
Note that because this is C++, a lot of housekeeping is hidden; for
example, I only had to define the variable 'echo' in order to create
the echo task. There is no reason it can't be done in C, I just chose
not to.
--
J. Alan Eldridge (alane AT wozzle DOT linet DOT org)
- Raw text -