Columns


Questions & Answers

Dynamic Program Suspension

Kenneth Pugh


Kenneth Pugh, a principal in Pugh-Killeen Associates, teaches C and C++ language courses for corporations. He is the author of C Language for Programmers and All On C, and was a member of the ANSI C committee. He also does custom C programming for communications, graphics, image databases, and hypertext. His address is 4201 University Dr., Suite 102, Durham, NC 27707. You may fax questions for Ken to (919) 489-5239. Ken also receives email at kpugh@dukemvs.ac.duke.edu (Internet) and on Compuserve 70125,1142.

Q

We enjoy reading The C Users Journal, more than other programmers' magazines. We think we have detected a lack of, or need for, a dynamic program suspender. Perhaps a reader of CUJ might have a solution. We do not know how to write one or even how to suggest one could write it, but here is a list of its operational parameters:

1. Activate by a hot-key or time clock event.

2. Active program, in-memory data, and other system requirements stored on disk.

3. Normal MS-DOS environment becomes active (as if the previous program had terminated normally).

4. At a later time (whenever required), the suspended program could be reloaded from either a normal MS-DOS environment, or even spawned/executed from within an active program.

5. On resumption, program should continue execution as if nothing had happened.

6. Repeat above as required.

This utility has been sorely missed by us for a while now. We often write small programs to amuse ourselves; however, they sometimes require days to complete. In a normal working environment this is not a welcome feature of any program. If we could use the spare time available, usually at night, to run our toy programs, we would be able to complete our toying. Example toy programs:

We thank you from Australia,

Jim Eadie
George Leake
Melbourne, Australia

A

There are several ways to perform the operations you have requested. The simplest is to get a multitasking overlay to MS-DOS, such as DESQview or Microsoft Windows, or a multitasking operating system that has multiple DOS windows, such as OS/2.

These systems allow you to run multiple programs simultaneously. They vary in the control that you have over the percentage of time that each program is allowed. The simplest one to set up and use is DESQview. I have used it for a number of years to perform operations similar to the ones you requested.

DESQview provides true timesharing between programs that can fit into memory. Each program runs in its own window. The window that receives the keyboard input is the foreground window. The remainder of the windows are background windows. You can switch the foreground window at any time using the Alt key.

Every clock tick (about 18 times/second), the executive is called and decides which program to execute next. In the setup procedure, you specify the percentage of time to be devoted to the foreground program and the background programs. If you specify a very small percentage or even zero percentage for a background program, then you will hardly notice that it is present.

DESQview will use extended memory as well as conventional memory to run programs. If all the programs you are attempting to run cannot fit into memory, DESQview will swap out background programs to disk. When you switch to a swapped-out program, it will swap in that program and swap another out to disk.

You have a fair amount of control over each window. You can specify that the program is not to be swapped out. This would be the case for a program that needs to respond to interrupts, such as a communications program. You can prevent the window from being closed until the program terminates. I use this for word-processing windows to be sure my files are saved before exiting DESQview. You can prevent the CPU from being shared when the program is the foreground program. You can also say that the program should not run when it is in the background.

To use DESQview in your application, you can open up a window and run your long-running program in it. The window should be set up to run only when it is the foreground window, to be not closable, and to be swappable. Then open another window or several other windows and run your daily programs in them. When you are through for the day, simply switch to the long-running program.

Alternatively, you could purchase or obtain a routine like X-SPAWN, which swaps the current program out to disk and spawns another program. When that program terminates, the current program is swapped back in. The program that executes could be COMMAND.COM, so a DOS command prompt would appear. When you typed EXIT, the previous program would be resumed.

The program performing the XSPAWN would contain the algorithm you are computing. It could check periodically or on a signal for keystrokes. If a keystroke occurred, it would call XSPAWN. I prefer using the DESQview approach. Programs do not need to be aware that they are sharing the machine with any other programs. (KP).

Error Handling

Q

This response comments on your March 1993 column, wherein James Brown explained how he uses gotos to consolidate error handling near the bottom of a routine. I often use a similar technique, which is illustrated in Listing 1. The basic concept is similar in that the code falls through terminating procedures. However, for the benefit of some purists, this method does not use gotos although it does use multiple returns. The code sample also provides for an error message although this is not necessary. This method is particularly handy where, as in the code sample, the cleanup code is not called from within the same function.

Andy Levinson
Studio City, CA

A

Thank you for your contribution. It demonstrates a nice way of centralized error handling without gotos. It also spurred me to think more about error handling. The complexity of error handling can be reduced if each object, as a buffer or a file, contains its own internal state. The state is set when an initialization function is called and then tested when a termination function is called. These functions need to be called explicitly, rather than implicitly, as is done in C++.

Listing 2 shows an example following James Brown's listing in the March issue. The Buffer_initialize and Buffer_terminate routines are fairly simple. The state of a Buffer variable is kept in the variable itself. If the value of the variable is NULL, then no memory is currently allocated. The only difference between this and using just malloc and free is that the value of pointer is reset to NULL when it is freed in Buffer_terminate. Note that each Buffer variable has to be initialized before it can be terminated. However, it can be allocated unsuccessfully (i.e. Buffer_allocate returned FAILURE) and Buffer_terminate can be called without causing a problem. Listing 3 is an example that follows along the lines of your code.

The File structure includes the current state and the buffer pointer. Normally, I would write the open and read operations as separate functions. They are kept together here to parallel your example. I expanded your implicit states of 1 and 2 to the four that are listed in enum File_state, even though the operations upon termination are the same in two cases.

As I do with Buffer_initialize and Buffer_allocate, I would separate the operations of initializing and opening the file. This would add a line of code to initialize each File variable, but it would simplify the testing of other operations' return values.

The code in Listing 4 shows how multiple File objects could be used in the same function. Each File variable has to be initialized. However, File_terminate can be called without erroneous results for variables that have not been successfully initialized.

These functions might seem like overkill for the simple errors that can be generated with these types. However, the same technique can be applied to more complex objects.