[comp.sys.mac] Multitasking and interactivity issues

ldo@waikato.ac.nz (Lawrence D'Oliveiro) (01/13/90)

MultiFinder has been accused of not having "true" multitasking,
in that it requires applications to cooperate and not hog
the CPU to themselves.

Elsewhere on the net, somebody has been asking for efficient
techniques to implement the traditional "command-period" way of
interrupting a lengthy operation.

After reading the debates on this and other issues, I'd like to
volunteer some opinions on this business of the right way to do
multitasking on a desktop machine, and the whole issue of writing
interactive software. I welcome constructive comments on
these matters.

The Mac is an interactive computer system. I like to think
it's the most interactive computer system you can currently
buy, for any money. What do I mean by "interactive"? I mean
that the system (and all the good applications) never (well,
almost never) "turn their back" on you to go away and perform
some lengthy operation. At the very least, a good piece of
software puts up some sort of progress dialogue box, with,
say, a thermometer indicating how much of the operation has
been performed so far, and a "Stop" or "Cancel" button (which,
by the way, I prefer to command-period).

I agree, it takes some CPU time to maintain this in-progress
display, and keep polling for a button click. But that's
the price you pay for interactivity. Remember when time-
sharing systems first came out? They had a _much_ higher
overhead than the older batch systems. But that was the
price you paid for the increased responsiveness, which
dramatically changed the way computers were used. I think
desktop systems like the Mac are just as big a quantum
jump over timeshared systems, for exactly the same reason.

The MultiFinder argument is partly over the lack of inter-
process communication facilities (being addressed in System
7, or so I hear), and partly over the issue of preemptive
(where different tasks can run concurrently without having
to explicitly give up control to one another) versus non-
preemptive multitasking.

I agree, preemptive multitasking can be very useful, and would
simplify some operations. But polling still has an important
place.

Consider the spinning cursor that some Mac programs put up
when performing a lengthy operation (and its variants--the
Finder's wristwatch with the moving hand, the new Installer's
turning globe, Mathematica's nifty "string-art" display, etc).
These displays aren't just for show, they let the user know
that something is actually going on. If the operation is
particularly lengthy, that thermometer I mentioned earlier
might creep along extremely slowly. Or, the operation might
be of indeterminate duration, so no thermometer is
appropriate. The animated cursor is a particularly useful
indicator in these cases.

Some people have suggested that cursor animations might be
most conveniently done in a separate concurrent task. Even
without preemptive multitasking, you can do asynchronous
cursor animation on the Mac by specifying a piece of code to
be executed during the vertical retrace interrupt (a "VBL
task"). *I don't think this is a good idea.*

Why? Because then that pretty animated display becomes meaningless.
An animation done by periodic polling at least gives you the
assurance that something is really happening; if the program
should take exceptionally long over a single iteration, or
(perish the thought) hang or crash, the animation will stop.
With asynchronous animation, the user could be waiting for
quite a long while before suspecting that something might
be wrong.

I know, you're already saying, "Trust me--with my code, it'll
never happen." Sure...

Even without the animated cursor, there's still the matter
of that "Cancel" button. Why poll? you may ask. Why not,
under a preemptive multitasking system, have a high priority
task, doing nothing at all, but waiting for a click on
Cancel? Then, when it wakes up, it initiates the appropriate
operation-cancelling action.

The question is, what exactly *is* the operation-cancelling
action? Is it enough to just kill the task performing the
lengthy operation? Fine, this is often good enough. Just as
often, however, you will need to do some cleanup (free up
temporary memory, close files and network connections, etc).
The task that was doing the operation has to make a note,
as it allocates each resource, that it has done so, so that
it can be freed during a subsequent cancel. You still have
to do this in the synchronous case, but here, all kinds of
subtle timing problems can arise: you have to be very careful
not to leave *any* small "timing window" during which a
cancel will leave something in an inconsistent state. Such
as a cancel occurring in between allocating some memory
and flagging that you've allocated the memory (whether you
perform those steps in either order). Various systems
offer ways to take out locks, temporarily raise your priority,
or disable rescheduling or other interrupts, to keep
these operations indivisible.

It's often so much easier just to do periodic polling.

By the way, this is why I think it's a good design feature
that the Mac doesn't have an equivalent of the Control/C
interrupt sequence in various other operating systems.
By not having a built-in interrupt (for the normal user,
anyway--the "programmer's switch" doesn't count!), developers
are forced to think about how they will provide an interrupt
facility to the user. The operating system simply cannot do
it automatically, in a clean way.

Having said all that, I'd like to add that, yes, I want
preemptive multitasking. But I think that there is a right
way to do it, and a wrong way.

People have a habit of using multiuser computer systems as
examples, when they talk about multitasking. Consider the job
of a typical time-shared, multiuser computer system: it is
running several tens or hundreds of simultaneous users, all
working on unrelated things, all competing for common
resources--CPU, memory, disk space, I/O bandwidth. In this
situation, the primary job of the operating system is, not
to help users (and programmers) run their programs, but to
*prevent* them from doing certain things--i e, hogging all
the resources at the expense of other users.

Now consider a single-user, multitasking computer system from
the year 1992, complete with stereo video display, running
the latest WarpDrivez spreadsheet-cum-4D-visualiser-cum-
bottle-opener. The program is running three separate tasks
(this is a simple example...): one is printing a document,
another is doing background recalculation on another document,
and the third is handling the user interface. Naturally the
user-interface task has the highest priority. The user scrolls
over the worksheet, and a 3D projection of a tesseract scrolls
into view. Let us suppose the image isn't already being cached
somewhere, so it has to be generated. Let's further suppose
that the user-interface task has the job of generating the
image, because the application developer decided to do things
that way. In any case, the image only takes a second to
generate the first time, and the developer decided that the user
wouldn't want to do anything else in the meantime.

So, during that second, the user-interface task hogs the
entire CPU, bringing the printing and recalculation tasks to
a halt.

What's the reflex response of a typical multiuser operating
system to a situation like this? Answer: lower the priority of
the user-interface task. I submit that, in the single-user
environment, this is *not* a clever thing to do. Either it has
an effect--decreasing the responsiveness of the user interface--
which is undesirable, or it has no effect, which is pointless.

The situation with multiple concurrent applications running
offers similar problems. The convention with a system like OS/2
(as I understand it) is to give higher priority to the "foreground"
application. But this might not be appropriate. I might be
working in a word processor, while keeping one eye on a stock
market display in a window (perhaps partially-obscured)
belonging to a background application. The background display
doesn't need much CPU time to update, but when it wants it,
it should get it *now*, even if the automatic repagination in
the word processor in the foreground suddenly gets sluggish
(though I don't want the word processor losing keystrokes!).

The point is, if I'm running several concurrent applications,
I should be able to assign priorities to them, without having
to worry about trying to defeat some automatic priority-
adjustment algorithm. Application priorities are a matter
between me and the applications, and are none of the operating
system's business.

Conversely, I don't want to know that an application consists
of three separate tasks, or 10 tasks, or 100, and that I
should have to assign priorities to all of them. The operating
system doesn't know the function areas assigned to these tasks
(e g background printing, pagination, bottle-opening); only
the application can present the intra-application task-management
problem to the user in a comprehensible fashion.

In summary, a personal computer system needs *cooperative*,
not competitive, multitasking, and needs to be designed accordingly,
not as a cut-down version of a multiuser operating system. I
think even round-robin time-slicing (forced periodic rescheduling)
of tasks is a bad idea; it costs CPU cycles to implement, and if
I can't give enough time to all the tasks I'm trying to run, that
means I'm trying to run too many things at once, and it's time to
add another processor.

Of course, multiprocessing is another story...

tonyrich@titanic.cs.wisc.edu (Anthony Rich) (01/15/90)

In article <1990Jan13.105048.11530@waikato.ac.nz> ldo@waikato.ac.nz
(Lawrence D'Oliveiro) writes:

[Many insightful comments about how tightly-coupled a computer user
 is with active programs on a Mac in terms of visual feedback, program
 interruptability, and priorities, and how tight that coupling could
 and should be on a "true multitasking" personal computer.]

> In summary, a personal computer system needs *cooperative*,
> not competitive, multitasking, and needs to be designed accordingly,
> not as a cut-down version of a multiuser operating system.

This is a good point.  Multiuser, multitasking OS's like Unix were
designed to keep the *machine* productive, occasionally at the expense
of wasting an interactive user's time.  That made sense when hardware
and machine time were (or seemed) more expensive than people's time.

Now it's the other way around, and the Mac is a good example; its goal
is to keep the user productive, not to keep the processor busy.  (In
fact, processors on single-user machines are "idle" virtually ALL the time.
But who cares?  As the old saying goes, "Better to have it and not need it
than to need it and not have it."

So in the mad scramble to add features of multiuser operating systems
to single-user machines, it's important to remember that some of those
features were designed with different goals in mind, and those goals
weren't necessarily user-friendly!

It would be interesting to have a Mac operating system which allowed a user
to choose either cooperative or competitive multitasking at any time.
(By clicking a button, of course!  Instantly toggle between MultiFinder and
A/UX-with-a-MultiFinder-interface, maybe?)

I wonder which mode people would end up using most, and for what reasons?
--
------------------------------------------------------------------------
Email:       tonyrich@titanic.cs.wisc.edu  Phone:  608-271-8450
Disclaimer:  The opinions above are mine.  Others may agree or disagree.
------------------------------------------------------------------------

ksand@appleoz.oz.au (Kent Sandvik) (01/19/90)

tonyrich@titanic.cs.wisc.edu (Anthony Rich) writes in article <9534@spool.cs.wisc.edu>:
      
      This is a good point.  Multiuser, multitasking OS's like Unix were
      designed to keep the *machine* productive, occasionally at the expense
      of wasting an interactive user's time.  That made sense when hardware
      and machine time were (or seemed) more expensive than people's time.
      
      Now it's the other way around, and the Mac is a good example; its goal
      is to keep the user productive, not to keep the processor busy.  (In
      fact, processors on single-user machines are "idle" virtually ALL the time.
      But who cares?  As the old saying goes, "Better to have it and not need it
      than to need it and not have it."


An interesting approach in future would be to consider CPU power with
the same methaphor as electrical power.  I.e.  if you need additional
crunch in order to create that ultimate 3D-multimedia spreadsheet, you
could make use of idle CPU time on machines connected to the same
backbone network. 

Industry standards like NCS and the new OSI approach to Distributed
Computing will eventually lead to this new computing environment.  IMHO
the key to acceptance would be a totally transparent environment, where
a) the end user does not need to care about assigning tasks, defining
priority levels or scheduler parameters and b) where the system does not
give networking CPU access if the end user suddenly starts working on
his/her own workstation. 

/ksand
-- 
Kent Sandvik, Network Ninja         --  Apple Australia Developer Tech Support
{uunet,mcvax,enea}!munnari!appleoz.oz!ksand, ksand@appleoz.oz.au (OR ksand@apple.com)
AppleLink: AUSTAUX    Disclaimer: "Opinions expressed are not Apple's opinions"

mitchell@cbmvax.cbm.commodore.com.commodore.com (Fred Mitchell - PA) (01/23/90)

In article <1990Jan13.105048.11530@waikato.ac.nz> ldo@waikato.ac.nz (Lawrence D'Oliveiro) writes:
>
>MultiFinder has been accused of not having "true" multitasking,
>in that it requires applications to cooperate and not hog
>the CPU to themselves.
>...
>In summary, a personal computer system needs *cooperative*,
>not competitive, multitasking, ...

I _very strongly_ disagree. On the Amiga, you have the best example of
pre-emptive multitasking that I have ever seen on a micro. And the number
ONE thing that you have is SPEED! If my program dosen't have to make
repeated calls to the OS, it can run that much faster. I don't see any
advantages to having a 'cooperative' OS at all. It tends to get in the way,
and hints at a fundamental flaw in the initial design. I fail to understand
why Macs can't go pre-emptive anyway. All you do is save all the registers,
go to the next task, and load that task's registers, and hop right in where
it left off before! Shared resources can use semaphores to arbitrate usage.
Sound pretty simple to me! Why is that not possible under the Multi-Finder (or
Finder for that matter)?  :-(

>...not as a cut-down version of a multiuser operating system. I
>think even round-robin time-slicing (forced periodic rescheduling)
>of tasks is a bad idea; it costs CPU cycles to implement,

Not nearly as much as cooperative costs you!

Then again it's unfair to compare a personal computer to a multi-user
system. (Or is it? :-) 

	-Mitchell
	 mitchell@cbmvax.UUCP

jay@mitisft.Convergent.COM (Jay O'Conor) (01/24/90)

In article <9430@cbmvax.cbm.commodore.com.commodore.com> mitchell@cbmvax.cbm.commodore.com.commodore.com (Fred Mitchell - PA) writes:
>In article <1990Jan13.105048.11530@waikato.ac.nz> ldo@waikato.ac.nz (Lawrence D'Oliveiro) writes:
>>
>>MultiFinder has been accused of not having "true" multitasking,
>>in that it requires applications to cooperate and not hog
>>the CPU to themselves.
>>...
>>In summary, a personal computer system needs *cooperative*,
>>not competitive, multitasking, ...
>
>I _very strongly_ disagree. On the Amiga, you have the best example of
>pre-emptive multitasking that I have ever seen on a micro. And the number
>ONE thing that you have is SPEED! If my program dosen't have to make
>repeated calls to the OS, it can run that much faster. I don't see any
>advantages to having a 'cooperative' OS at all. It tends to get in the way,
>and hints at a fundamental flaw in the initial design. I fail to understand
>why Macs can't go pre-emptive anyway. All you do is save all the registers,
>go to the next task, and load that task's registers, and hop right in where
>it left off before! Shared resources can use semaphores to arbitrate usage.
>Sound pretty simple to me! Why is that not possible under the Multi-Finder (or
>Finder for that matter)?  :-(

Sigh... Will this never end?  For nearly 10 years I was an O/S Software
Engineer for a company that had it's own proprietary COOPERATIVE multitasking
O/S.  It is _very_ possible to have an effective, efficient cooperative
multitasking O/S.  In terms of efficency, a cooperative multitasking
scheme has less overhead since processes aren't being switched while they have
useful work to do.  In terms of effectiveness, no application had any effect
on the response of another.  It worked well because the system was very I/O
intensive.  All this I/O time was available for other processes.  Badly behaved
applications that didn't release the CPU were detected very quickly during 
development.  Only one application (the assembler) had O/S calls inserted in
the code to explicitly give up the CPU.  This was the most CPU intensive
application on the system.
It is not as simple to implement a preemptive multitasking O/S as you indicate
above.  The entire state (context) of a process must be saved between process
switching.  Unfortunately, the processor registers are not all of the process
context.  On the Mac, currently the only place where a process state can be
guaranteed to be stable is at the process switch times Apple has defined for
MultiFinder (GetNextEvent, WaitNextEvent, etc.).  Even the UNIX kernel doesn't 
preemptively switch processes while executing in the kernel.  It doesn't need
to - perfectly reasonable response can be acheived without it.  But it does
interfere with Unix's abiltity to be a real-time O/S.  I point this out to
illustrate that even what many people consider to be the foremost preemptive
multitasking O/S isn't perfectly preemptive.  But people don't complain about
Unix (unless they want a realtime O/S).
All this is not to say that MultiFinder is perfect.  Flaw number one is that
processes don't switch during disk I/O.  Even if they did, I'm not sure how
effective that would be without DMA.  Flaw number two is that all output to
the display is very CPU intensive - obviously.  In a serial terminal based 
system, a cooperative multitasking O/S can service other processes during 
screen updating - the Mac can't.  
Instead of debating the merits of preemptive vs. cooperative multitasking
O/Ss, why not debate the issues that would make the Mac a more effective
multitasking system regardless of the policy used - THE MAC NEEDS DMA AND
A QUICKDRAW COPROCESSOR.  Let's identify wasted CPU time and gripe about
how that time isn't being given to other processes.
On a similar note, some people on the net have griped about how the Mac
doesn't have (and won't, even under 7.0) _protected_ virtual memory.
How about getting a discussion about this going.  I understand _why_ it's
going to be difficult to implement seperate protected address spaces for
processes - the question is what is going to be done to the Mac O/S to 
overcome these hurdles in the future.  One problem that has to be taken
care of are data structures (such as the window list) that currently
logically thread their way through what would be all process address spaces.

>
>>...not as a cut-down version of a multiuser operating system. I
>>think even round-robin time-slicing (forced periodic rescheduling)
>>of tasks is a bad idea; it costs CPU cycles to implement,
>
>Not nearly as much as cooperative costs you!

False.  Cooperative costs LESS if implemented correctly.
See above.  The Mac needs to have more time spent waiting for I/O.

>
>Then again it's unfair to compare a personal computer to a multi-user
>system. (Or is it? :-) 

The boundaries are blurring.  The one boundary that I hope will remain
intact is that personal computers are not shared by multiple people at
the same time.  I'd like to see the Mac evolve into an efficient multi-
tasking system, not a multiuser system.

(now getting down off my soapbox :-) )

>
>	-Mitchell
>	 mitchell@cbmvax.UUCP


Jay O'Conor
UNIX O/S Sofware Engineer
Unisys/Convergent