In computer science, a program refers to a set of instructions for the CPU (central processing unit) to execute. In Linux, a process is simply the name for a program that’s being executed. In this post we will look at how processes are created and how we can communicate with them.
When the computer boots up, the kernel (the ‘middle man’ between the operating system and the CPU) loads a program called init (or systemd) into memory and it begins executing; this is the first process.
From here on, processes are created by duplicating an existing process. This is known as a fork. The
fork() system call asks the kernel to essentially copy the existing process and give the new process some space in memory. The original process is now referred to as the parent, and the duplicate becomes the child.
Each process has a unique PID (process identification number). The number 1 is reserved for init/systemd and you’ll often see processes assigned PIDs from 2 through 32,768, but they are not necessarily assigned in sequential order.
Let’s look at a C program that utilizes
fork()to create a new process,
getppid() to display the PID of the child and parent processes, and
wait() to control the flow of execution:
int status; printf("I am the parent, my PID is %d\n", getpid());
printf("My parent's PID is %d\n", getppid());
printf("I am going to create a new process...\n"); child = fork(); if (child == -1)
// fork() returns -1 on failure
else if (child == 0)
// fork() returns 0 to the child process
printf("I am the child, my PID is %d\n", getpid());
printf("My parent's PID is %d\n", getppid());
// fork() returns the PID of the child to the parent
wait(&status); // wait for the child process to finish...
printf("I am the parent, my PID is still %d\n", getpid());
I am the parent, my PID is 26407
My parent's PID is 2040
I am going to create a new process...
I am the child, my PID is 26408
My parent's PID is 26407
I am the parent, my PID is still 26407
getppid() in the child process returns the same value as
getpid() in the parent process.
When this program finishes executing, the child and parent processes terminate and the flow of execution goes back to the where the program was invoked (e.g. the shell). If you ran this program from a Bash shell, like I did, you can use
echo $$ to display the PID of the current Bash process.
Notice how the parent PID in our C program is the same as our Bash PID. This means that Bash forked a new process to execute our C program and waited for it to finish, just like we did in our C program. Once it terminated, the flow of execution returned back to Bash (the parent process).
Now let’s see what programs are currently being executed on our system.
We will use the
ps command with some additional options that provide detailed information about the processes running on our system. The option
-a lists processes of all users on the system,
-u gives us details about the processes, and
-x lists processes that run unobtrusively in the background (these are known as daemons and usually end with a d, like systemd).
Sometimes the output of
ps aux can be overwhelming and we want to narrow down the list of processes. We can use
pgrep to lookup ones that match a specific pattern of text. For example,
pgrep -l chrome will search processes metadata for the pattern ‘chrome’, then display the PIDs of those processes along with the program’s name.
Now that we know how processes are created and how we can view running processes on our system, let’s see how we can control them.
kill is a shell builtin command that is used to send a signal to a process. By default, that signal is SIGTERM (for terminate). If we wanted to terminate one of our chrome processes we can invoke
kill with the PID as an argument.
If we want to terminate all processes that match the pattern ‘slack’, for example, we can use
Some processes will receive the SIGTERM signal from
kill, and handle it in a way where the process doesn’t actually terminate. For example, here is a program that uses
trap to respond to
#!/usr/bin/env bashwhile true; do
echo "my PID is $$"
trap "echo YOU CANNOT TERMINATE ME" SIGTERM
sleep 2 # for demo purposes
If you want to be sure you are terminating a process you must use SIGKILL or SIGSTOP. These are the only two signals that cannot be ignored by
trap. All of the signals can be displayed using
kill -l and they have corresponding numbers that can be used instead of the all-caps words. For example
kill -15 is the same command as
Here I will use the same program as above, but use the
-KILL flag to force termination:
Kill sounds like a violent word, but it’s not always used for signaling death sentences. SIGSTOP is a signal used for stopping a process, which can later be resumed by using the
fg (foreground) command.
Here is the same program being stopped and continued:
- Processes are running instances of programs.
- They are creating by duplicating an existing process (forking)
- They each have a unique PID
- We can use
killto send signals to them