[comp.sys.mac.system] Why I Would Like "True Multitasking"

lupini@cs.sfu.ca (Peter Lupini) (06/28/91)

Hi,

First of all, let me say that I think the mac is a *fantastic* machine - I 
use my IIci for all my research, plus a little graphic arts on the side.

But...without wanting to start up the whole "true" multi-tasking debate, here 
is what I miss most about the current mac system:

I write many programs each day as part of my research. Usually, these are
numerically intensive tasks.  When I used to do this on an Amiga, I could just
write my program, run it, and then open a new window and keep working.  I could
even assign a priority to my "background" task so that I could do useful work
in the foreground.

With the Mac, I use THINK C.  But when I run a program, I have no way of doing 
this.  I must wait until the program has completed execution.  I can't even 
switch to my terminal session and work on the remote machine.  I guess my 
definition of "True Multi-tasking" is that I can write a program without 
knowing anything about multi-tasking, and run it in the background.

So here are my questions:
1) Am I missing something obvious here?  I am assuming that I have to make my
   program "multi-finder" aware or something, and make it be smart about not
   taking all the cpu time while it is running.  This seems to be an incredible
   pain when I'm just writing quick 'n dirty programs which may be used for 
   only a week or so.

2) Does apple have plans to modify the operating system so that this is 
   possible?

3) Am I the only one who has this problem?  I would have thought that anyone
   who uses the mac to write programs that are not specifically for the mac
   user interface (eg. most of my interface consists of a unix-type command
   line!) would run intot this problem.

Any answers/comments would be appreciated!

science@oasys.dt.navy.mil (Zimmermann) (06/28/91)

I agree 100% ... I too would like easy multitasking for simple
programs written in THINK C.  (It would be nice if the multitasking
included a measure of protection from my program locking up the
machine, but I guess that's beyond the realm of what's possible for
the next few years (System 8?).)  But a little library function to call
sporadically, perhaps, to handle events generated by other programs in
a natural way, wouldn't seem to be too tough to write, for somebody
who knew Mac internals to a fair degree.  Better yet, but no doubt
tougher to produce, would be an interrupt-driven routine which would
break in on a running program (as the THINK C debugger does) and give
some time slots to other processes.  But writing one of those would
probably be a job for a wizard at Symantec with access to the
compiler's inner workings.

MacForth programs, many many years ago, had simple multitasking that
Don Colburn designed into the language (and this was pre-MultiFinder,
note!) so that whenever one program running executed a particular
routine (either calling it voluntarily, or automatically when asking
for disk or keyboard/screen I/O) control passed on to the next in the
tasking loop ... worked nicely within the little universe of Forth
programs, and allowed a lot of productive work to go on at once.

I am particularly interested myself in building big free-text inverted
index database files in background ... it takes several minutes per
megabyte to parse and sort pointers to all the words in a text file
(on current-genearation Macintoshes), and doing this kind of process
in background is an ideal way to operate.  I can already do it nicely
that way on UNIX machines --- so why can't I on the Mac?  Actually, a
few years ago, I did just this, exceedingly crudely, in a program
called "MultIndexer", what I called a "MultiFinder-tolerant" (since
it wasn't "friendly"!) way to do background index-building.

What the heck ... I doubt that it will work any more, but here is the
key routine, "check_events()", which I scattered calls to throughout
my numbercrunching/quicksorting program.  Maybe somebody kind can tell
me whether an update or modification or analogue to this type of thing
could still work these days?!

 -------------THINK C code follows--------------------

/* function to check for user interruption of operations (for use in the
 * Macintosh version of this program only) ... call SystemTask() to give
 * desk accessories a bit of time, and then check for non-null events
 * with GetNextEvent() ... if something comes along, let the user choose
 * to exit the program or to carry on if it's a keystroke .... otherwise,
 * just ignore the event for now.  Call this pretty often, for multifinder
 * compatibility.... the 'greed' parameter (default -5) tells how often
 * to give other jobs a chance.  greed = -1 is most generous; as greed
 * gets more negative, longer intervals elapse before giving up control.
 */
 
#ifdef LIGHTSPEED
 
void check_events ()
  {
        EventRecord my_event;
        char cmd[256], *gets();
        extern long greed;
        void exit();
        static unsigned long trigger_time = 0;
        
        if (TickCount () < trigger_time)
                return;
        
        trigger_time = TickCount () - greed - 1;
 
        SystemTask ();
        if (GetNextEvent (everyEvent, &my_event))
          {
                switch (my_event.what)
                  {
                        case nullEvent:
                        case mouseDown:
                        case mouseUp:
                        case keyUp:
                        case autoKey:
                        case updateEvt:
                        case diskEvt:
                        case activateEvt:
                        case networkEvt:
                        case driverEvt:
                        case app1Evt:
                        case app2Evt:
                        case app3Evt:
                        case app4Evt:
                        default:
                                break;
                        case keyDown:
                                fprintf (stderr, "Quit indexing now?\n");
                                gets (cmd);
                                if (cmd[0] == 'y' || cmd[0] == 'Y')
                                        exit (0);
                                break;
                  }
          }
  }
 
#endif

 ----------------------end of C code---------------------

As you can see, it's crude, but it did work; I typically set the "greed"
parameter to give up control every 0.1 second or so, with decent results.

To update this, I wonder if there would have to be new events added to 
the list, or new calls made to new Toolbox routines?

Note that this thing using the above function only was able to switch
to another process under MultiFinder if the user clicked on the little
icon at the right-hand end of the menubar ... the routine did NOT 
properly recognize mouse clicks on other processes' windows.  That
needs to be fixed.  And since under System 7 nowadays one has to pull
down the menu at the right end of the menubar, rather than just click
on the icon, to switch foreground jobs, I expect that further surgery
is needed to make the check_events() function work.... 

Any suggestions/ideas/comments?  Tnx for reading this far, Mom ... am
sure you're the only one left.... :-)

Best,  ^z
      Mark Zimmermann, "science@oasys.dt.navy.mil"

bc@Apple.COM (bill coderre) (06/29/91)

lupini@cs.sfu.ca (Peter Lupini) writes:
|So here are my questions:
|1) Am I missing something obvious here?  I am assuming that I have to make my
|  program "multi-finder" aware or something, and make it be smart about not
|  taking all the cpu time while it is running.  This seems to be an incredible
|  pain when I'm just writing quick 'n dirty programs which may be used for 
|  only a week or so.

Peter: Without getting into a big argument about what "true
multitasking" is ("I dunno, but I knows it when I sees it") let me
just give you a pragmatic answer about writing your programs.

The bad news is: yes, you do have to write your programs in a special
way to allow Multifinder to switch them to the background.

The good news is: it isn't that hard to do, it ends up being pretty
much what you might think of doing in a non-multitasking OS, and the
code is available as templates and easily re-used.

The "Programmers Guide to Multifinder" from APDA provides the precise
details of how to do it, but so do several articles in MacTutor,
MacTechQuarterly, and other mac programming journals.

Code is available from APDA, from ftp.apple.com (I believe, I haven't
checked recently), and from those magazines.

I also believe that The Macintosh Programming Primer (volume 1, c or
pascal version) provides some sample code and explanations about the
methodology required.

The basic strategy revolves around the program's Main Event Loop. In
the "usual" form of this loop, the program checks to see if any events
are pending by calling GetNextEvent, then dealing with them.

In the Multifinder-friendly app, the program calls WaitNextEvent,
and then chooses what to do with events it receives belonging to it,
determined by whether or not it is "busy calculating".

The simple approach is to set a global flag (like gBusyCalculating)
when you have finished setting up to do the calculation. When the Main
Event Loop sees the flag set, it ignores most events (except, for
example, a command-period keypress), and instead calls a routine that
does a small amount of the calculation in question (for example,
DoOnePixel).

By tuning the parameters to WaitNextEvent, you can determine just how
much of your CPU will be eaten by the background processing.

This method requires a little code, but not a whole lot. Indeed, I
have a standard Mac Main Event Shell that I add to code I'm porting
from Unix that provides all the necessary operating system support
code I need. It even provides an acceptable user interface for no
particular extra charge.

There are obviously more issues to multitasking in the MacOS than I've
covered, but don't think it's very hard to do at all.

bill coderre
who actually wrote Mac code before Apple hired him

peirce@outpost.UUCP (Michael Peirce) (06/29/91)

You forget that the Mac was not designed to be a *programmers* computer,
rather it was designed to be a *users* computer.  On the original
Mac you couldn't even program on it - you had to compile your code
on a Lisa, then bring it over.  The trade off is that to make easy
to use programs, it's often somewhat of a pain to program.


Having said that, you might check into using MPW.  MPW *was* meant
to be a programmer's environment - even if it had to sacrifice some
Mac-ness.  With MPW there's more to master than with THINK C, but it 
provides a nice command line environment - not unlike a Unix or VMS system.  

And, here's really why I recommend it to you, you can write non-Mac-like 
programs as an MPW tool that MultiTasks without dealing with event loops.  
All you need to do is sprinkle calls to SpinCursor() throughout your code.

Not only does this spin the cursor, but using a little magic it takes
care of all the event stuff for you enough that you can switch to
other programs in MultiFinder and run other Apps (like terminal sessions)
while your CPU bound non-Mac-like program churns away.

The MPW shell will contain all your program's output (from either
printf or writeln calls) and you can even redirect it (like in Unix
or VMS).  If you've used "big" machines, you'll feel right at home
in MPW.

Try, you might even like it...

-- michael

--  Michael Peirce         --   outpost!peirce@claris.com
--  Peirce Software        --   Suite 301, 719 Hibiscus Place
--  Macintosh Programming  --   San Jose, California 95117
--           & Consulting  --   (408) 244-6554, AppleLink: PEIRCE

frain@cis.ksu.edu (Jerry Frain) (06/30/91)

peirce@outpost.UUCP (Michael Peirce) writes:

>You forget that the Mac was not designed to be a *programmers* computer,
>rather it was designed to be a *users* computer.

Gee, I always thought that programmers *are* users.

>On the original
>Mac you couldn't even program on it - you had to compile your code
>on a Lisa, then bring it over.

Boy that makes me feel so much better.  Maybe we need to add a
card reader device driver to MacOS to make programming even more
fun.

>The trade off is that to make easy
>to use programs, it's often somewhat of a pain to program.

It doesn't have to be that way.  However, that is the way computer
evolution tends to go -- learn how to do it with much sweat and
tears and blood, then make an easier way to do it with the benefit
of hindsight.

  --Jerry Frain, frain@cis.ksu.edu

ingemar@isy.liu.se (Ingemar Ragnemalm) (06/30/91)

peirce@outpost.UUCP (Michael Peirce) writes:


>You forget that the Mac was not designed to be a *programmers* computer,
>rather it was designed to be a *users* computer.  On the original
>Mac you couldn't even program on it - you had to compile your code
>on a Lisa, then bring it over.  The trade off is that to make easy
>to use programs, it's often somewhat of a pain to program.

With the Think compilers around, and the tools available to modularize the
code better, I don't think the Mac is a pain to program. However, trying
to program in Megamax C or TML Pascal (pre-MPW) was a pain, especially
without the "modularizing" tools (OOP libs, TransSkel, MacApp etc).

(I wouldn't mind protcted memory when programming, though.)

-- 
Ingemar Ragnemalm
Dept. of Electrical Engineering	     ...!uunet!mcvax!enea!rainier!ingemar
                  ..
University of Linkoping, Sweden	     ingemar@isy.liu.se

krk@cs.purdue.EDU (Kevin Kuehl) (07/01/91)

In article <frain.678267470@orion> frain@cis.ksu.edu (Jerry Frain) writes:
   Gee, I always thought that programmers *are* users.

I think you missed Michael's point completely.  Just because a
programmer is a user does not mean a user is a programmer.  For
instance when I use my Mac at home I have completely different needs
than when I program my Sparc in my office.  I don't really need (or
want) the overhead of a preemptive scheduler on my Mac but I wouldn't
be without it on my Sparc.  Not because the Sparc is so much faster,
but because of the nature of the work I do on the machine.

   It doesn't have to be that way.

Sure it doesn't.  But so far I have not seen a computer that is both
really easy to use and really easy to program (I assume from
complaints that the Mac is hard to program).  The NeXT's I have worked
on come closer than most, but I still don't find them as easy to use
as my Mac.
-- 
Kevin Kuehl
krk@cs.purdue.edu

keith@Apple.COM (Keith Rollin) (07/01/91)

In article <54465@apple.Apple.COM> bc@Apple.COM (bill coderre) writes:
>lupini@cs.sfu.ca (Peter Lupini) writes:
>|So here are my questions:
>|1) Am I missing something obvious here?  I am assuming that I have to make my
>|  program "multi-finder" aware or something, and make it be smart about not
>|  taking all the cpu time while it is running.  This seems to be an incredible
>|  pain when I'm just writing quick 'n dirty programs which may be used for 
>|  only a week or so.
>
>Peter: Without getting into a big argument about what "true
>multitasking" is ("I dunno, but I knows it when I sees it") let me
>just give you a pragmatic answer about writing your programs.
>
>The bad news is: yes, you do have to write your programs in a special
>way to allow Multifinder to switch them to the background.

I missed the rest of Peter's post, but it seems to me that the "bad
news" as Bill puts it is not really relevent. In order to live with
MultiFinder, you just have to call GetNextEvent like you would in every
other application anyway. You only have to "write your programs in a
special way" if you want to be an Exceptionally Good Citizen. If Peter
is writing throw-away code, then he doesn't need to do this.

Of course, if you use a class library like MacApp or TCL, then you
don't even have to think about any of this; the class library will
handle it for you.

-- 
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc. 
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"But where the senses fail us, reason must step in."  - Galileo