Job Control

Objectives

  • FIXME

Our next topic is how to control programs once they’re running. This is called job control, and while it’s less important today than it was back in the Dark Ages, it is coming back into its own as more people begin to leverage the power of computer networks.

When we talk about controlling programs, what we really mean is controlling processes. As we said earlier, a process is just a program that’s in memory and executing. Some of the processes on your computer are yours: they’re running programs you explicitly asked for, like your web browser. Many others belong to the operating system that manages your computer for you, or, if you’re on a shared machine, to other users. You can use the ps command to list them, just as you use ls to list files and directories:

$ ps
PID    PPID   PGID   TTY   UID     STIME   COMMAND
2152      1   2152   con  1000  13:19:07   /usr/bin/bash
2276   2152   2276   con  1000  14:53:48   /usr/bin/ps

Every process has a unique process id (PID). Remember, this is a property of the process, not of the program that process is executing: if you are running three instances of your browser at once, each will have its own process ID.

The second column in this listing, PPID, shows the ID of each process’s parent. Every process on a computer is spawned by another, which is its parent (except, of course, for the bootstrap process that runs automatically when the computer starts up).

The third column (labelled PGID) is the ID of the process group this process belongs to. We won’t discuss process groups in this lecture, but they’re often used to manage sets of related processes. Column 4 shows the ID of the terminal this process is running in. Once upon a time, this really would have been a terminal connected to a central timeshared computer. It isn’t as important these days, except that if a process is a system service, such as a network monitor, ps will display a question mark for its terminal, since it doesn’t actually have one.

Column 5 is more interesting: it’s the user ID of the user this process is being run by. This is the user ID the computer uses when checking permissions: the process is allowed to access exactly the same things as the user, no more, no less.

Finally, Column 6 shows when the process started running, and Column 7 shows what program the process is executing. Your version of ps may show more or fewer columns, or may show them in a different order, but the same information is generally available everywhere.

The shell provides several commands for stopping, pausing, and resuming processes. To see them in action, let’s run our analyze program on our latest data files. After a few minutes go by, we realize that this is going to take a while to finish. Being impatient, we kill the process by typing Control-C. This stops the currently-executing program right away. Any results it had calculated, but not written to disk, are lost.

$ ./analyze results*.dat
...a few minutes pass...
^C

Let’s run that same command again, with an ampersand & at the end of the line to tell the shell we want it to run in the background:

$ ./analyze results*.dat &

When we do this, the shell launches the program as before. Instead of leaving our keyboard and screen connected to the program’s standard input and output, though, the shell hangs onto them. This means the shell can give us a fresh command prompt, and start running other commands, right away. Here, for example, we’re putting some parameters for the next run of the program in a file:

$ cat > params.txt
density: 22.0
viscosity: 0.75
^D

(Remember, ^D is the shell’s way of showing Control-D, which means “end of input”.) Now let’s run the jobs command, which tells us what processes are currently running in the background:

$ jobs
[1] ./analyze results01.dat results02.dat results03.dat

Since we’re about to go and get coffee, we might as well use the foreground command, fg, to bring our background job into the foreground:

$ fg
...a few minutes pass...

When analyze finishes running, the shell gives us a fresh prompt as usual. If we had several jobs running in the background, we could control which one we brought to the foreground using fg %1, fg %2, and so on. The IDs are not the process IDs. Instead, they are the job IDs displayed by the jobs command.

The shell gives us one more tool for job control: if a process is already running in the foreground, Control-Z will pause it and return control to the shell. We can then use fg to resume it in the foreground, or bg to resume it as a background job. For example, let’s run analyze again, and then type Control-Z. The shell immediately tells us that our program has been stopped, and gives us its job number:

$ ./analyze results01.dat
^Z
[1]  Stopped   ./analyze results01.dat

If we type bg %1, the shell starts the process running again, but in the background. We can check that it’s running using jobs, and kill it while it’s still in the background using kill and the job number. This has the same effect as bringing it to the foreground and then typing Control-C:

$ bg %1

$ jobs
[1] ./analyze results01.dat

$ kill %1

Job control was important when users only had one terminal window at a time. It’s less important now: if we want to run another program, it’s easy enough to open another window and run it there. However, these ideas and tools are making a comeback, as they’re often the easiest way to run and control programs on remote computers elsewhere on the network. We’ll look at how to do this later in this chapter.

Key Points

  • FIXME