UNIX Tutorial


12. Controlling processes

Commands covered in this section:   jobs, bg, fg, kill, nice, date, sleep

Up to this point in the tutorial, you've been running just one process at a time. However, since UNIX is a multi-tasking operating system, you are not limited to a single process — you can run an arbitrary number of processes simultaneously (within the constraints imposed by the resources available on the system). So far, in your interactions with the shell you've been launching a process and then waiting for it to complete and return control back to the shell (at which point you see the shell prompt again). This is called running a process in the foreground. It is also possible to run a process in the background. In this case, the program is launched and control is returned the the shell immediately, allowing you to run other commands. In the meantime, the initial process continues to run in the background. To place a process in the background when you launch it, add the ampersand character ('&') to the end of the command line (.e.g., "myprog &"). The ability to launch programs and move them between foreground and background execution is often called job control.

Exercise 12.1

We will use the date and sleep commands to create process that runs long enough for us to see that the process continues to run in the background. The date command simply prints the current date and time, while sleep just waits for specified amount of time and does nothing productive (yes, it's a very lazy program!). We are going to run date twice, with a sleep in the middle. We'll use parentheses to run the three programs as a group, but we still need to separate each command so the shell recognizes them as distinct entities (this is done with the semicolon). The output will be redirected to a file.

$ (date; sleep 60; date) > date.out &

Notice that the shell prompt returns immediately. Quickly enter the jobs command to see what processes are running:

$ jobs
[1]  + Running              ( date; sleep 60; date ) > date.out

The number is square brackets is the job id for the process you are running. Note that this is different from the process id, which is a unique number assigned to all processes running on the system. The job id is a sequential number assigned to the processes associated with the current shell you are running. The first one you launch is 1, the second one is 2, and so forth.

$ cat date.out
Wed Mar 12 16:38:42 PDT 2014

Keep doing this every few seconds until the second date shows up in the output file. It should be exactly 60 seconds later than the first date. You will also notice a message from the shell telling you the process that was running in the background has completed:

$ cat date.out
Wed Mar 12 16:38:42 PDT 2014
Wed Mar 12 16:39:42 PDT 2014

What if you've launched a process in the foreground and you want to move it to the background (perhaps because it's taking longer to execute than you thought and you have other work to do while the program runs). Since the process is running in the foreground, you can't give any other commands to the shell. Instead, you'll need some other way of communicating with the process. This is accomplished via a signal. Signals provide a means of sending an out of band message (that is, via some means other than the standard input) to a process. Many different types of signals are supported in UNIX. One instructs the process to clean up nicely and terminate, another instructs it to re-read its configuration files, etc. In order to place a foreground application in the background, you must first send it the suspend signal. This is accomplished by pressing CTRL-Z (hold the Control key and Z key down simultaneously).

Exercise 12.2

Run the same command used in the previous exercise, but omit the ampersand at the end:

$ (date; sleep 60; date) > date2.out

Notice that the shell prompt does not return immediately. Now press CTRL-Z. The shell prompt should return. Then use jobs to see the current status of the job:

$ jobs
[1]  + Suspended       ( date; sleep 60; date ) > date2.out

The job has been suspended. Now place it in the background using the bg command. If you have multiple jobs, you can specify which one to place in the background using "%N", where "N" is the job id (e.g., "%1" for job id 1). If you only have one job, you can omit the job id.

$ bg %1
[1]    ( date; sleep 60; date ) > date2.out &

Your shell prompt should return and the process will continue to execute in the background. If you later decide to move the process back to the foreground, this is done with the fg command.

$ fg %1

Now the shell prompt goes away and the process will only return control to the shell when it completes.

Let's suppose that, despite your best efforts, you've written a program that has run amok and is causing problems on the system (perhaps it has an infinite loop and is chewing up all the CPU cycles, or it's producing 1000 times more output than you intended and it's filling up a disk). How would you stop it? Well, if it's running in the foreground, you could send it the terminate signal. This is done by pressing CTRL-C. If the program is running in the background, you can send it the terminate signal using the kill command.

Exercise 12.3

Run the sleep command in the foreground. Wait a few seconds and press CTRL-C. This will terminate the sleep command and return control to the shell.

$ sleep 600

Now run the same command in the background. Then run jobs to verify that it is running and display the job id. Finally, instruct the program to exit using kill along with the job id for the process.

sleep 600 &
[1] 733

$ jobs
[1]  + Running                sleep 600

$ kill %1

$ jobs
[1]    Terminated             sleep 600

Note that the job id only exists in the context of the currently running shell. Once a program has been placed in the background, it is not necessary to remain logged in. The process will continue to run even after you log out. In fact, it is common practice to do this for long running jobs. However, once you've logged out, you can no longer refer to the process by its job id. You can, on the other hand, still access it using its process id, since this remains in effect during the entire time the process is running. To find the process id for a given process, we can use our old friends ps and grep.

Exercise 12.4

Run sleep in the background again. Then use ps and grep to find its process id and use kill to terminate it.

$ sleep 600 &

$ ps -ef | grep sleep
boris  1582  2125  0 11:41:22 pts/3    0:00 sleep 600

$ kill 1582

Note that when using kill with a process id, we just supply the process id (no '%' before the id). To confirm the process has been terminated, you can repeat the ps -ef | grep sleep command above.

One final note about processes: since UNIX is a multi-user system, your actions can have an impact on the other users of the system. Like other multi-tasking systems, UNIX uses a scheduler to divide up time on the CPU and allocate the slices of time to the various processes running on the system.

In general, a higher priority is given to interactive processes (such as the login shell you are using now). This makes the system much more pleasant to use for humans, since we tend not to like waiting around for machines to do work for us. Therefore, you want to be careful when running batch processes (for example, a sort of a huge text database) to avoid using up all of the CPU resources and making interactive use of the system frustrating for other users. The nice program is perfect for this application. You can use it to lower the scheduling priority of your batch process. Generally, this will not increase the run time of your process significantly, but it will often help to reduce its effect on interactive processes a great deal.

Exercise 12.5

Run sleep in the background again, this time using nice to lower the scheduling priority. Note that non-administrative users can assign nice values between 0 (no effect) and 19 (greatest effect). The higher the nice value, the lower the scheduling priority (in other words, the nicer the program becomes!).

$ nice +19 sleep 600 &

It's a good idea to use top to verify the nice level of your process and see what effect it's having on the system. You can also get a sense of this by just looking at how quickly the shell responds to interactive commands after you launch it. In the examples using sleep given here, the CPU usage will be trivial. However, you can apply the concepts you've learned here to any situation in which you need to run a batch process that is likely to use a significant amount of system resources.


Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.