Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ames!apple!usc!cs.utexas.edu!uunet!munnari.oz.au!comp.vuw.ac.nz!kaukau.comp.vuw.ac.nz!waikato!ldo From: ldo@waikato.ac.nz (Lawrence D'Oliveiro) Newsgroups: comp.sys.mac Subject: Multitasking and interactivity issues (long) Summary: Points for personal operating systems Keywords: multitasking,interactivity,personal Message-ID: <1990Jan13.105048.11530@waikato.ac.nz> Date: 13 Jan 90 10:50:48 GMT Sender: ldo@waikato.ac.nz Organization: University of Waikato, Hamilton, New Zealand Lines: 194 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...