Cloud Explainers
Home › Linux › Linux for Beginners, episode 5

Linux Processes vs Threads: When Each One Wins

Linux10 min videoPublished Oct 29, 2026

Processes vs threads on a real Ubuntu 24.04 server: PostgreSQL starts a process per connection, MariaDB a thread per connection. Four tested rounds: sharing memory (a real race condition), crashes, the cost of starting one, and using every CPU core. Plus a simple rule for when each one wins.

Linux Processes vs Threads: When Each One Wins: the full diagram
The whole picture, from the video's recap.

Processes vs threads

Every program on Linux runs as processes and threads. What's the difference, and when does each one win? Ana is picking a database for her shop, and three customers just connected to each of two. PostgreSQL started three new processes, one per customer. MariaDB is still one process. It went from seven threads to ten: one new thread per customer.

ana@ubuntu · two databases, three customers each
ps -u postgres -o pid,nlwp,args    PID NLWP COMMAND
     55    1 /usr/lib/postgresql/16/bin/postgres -D /var/lib/pos
     56    1 postgres: 16/main: checkpointer
     57    1 postgres: 16/main: background writer
     59    1 postgres: 16/main: walwriter
     60    1 postgres: 16/main: autovacuum launcher
     61    1 postgres: 16/main: logical replication launcher
    897    1 postgres: 16/main: ana shop [local] idle
    906    1 postgres: 16/main: ana shop [local] idle
    909    1 postgres: 16/main: ana shop [local] idle
ana@ubuntu · two databases, three customers each
ps -C mariadbd -o pid,nlwp,comm    PID NLWP COMMAND
    489   10 mariadbd

Same job, two designs. To see why, we'll look at what a process is, and what threads are. Then we'll test them in four rounds, on Ana's Ubuntu server: sharing memory, crashes, the cost of starting one, and using every CPU core. At the end, a simple rule for when each one wins.

What a process is

First, a program is just a file on the disk. A process is that program running. Linux copies the program into memory, gives it a number called a process ID, or PID, and runs it as a user. Each process gets its own private memory. Another process can't read it or change it. And one program can run as many processes at once.

What a process is: diagram from the video

Here's that on Ana's server. Her web server, nginx, is one program file. ps lists processes, and this one program is running as five. A master process runs as root, and four worker processes run as a user called www-data. Each has its own PID, and the NLWP column counts threads: each has one.

ana@ubuntu · one program, five processes
ls -l /usr/sbin/nginx-rwxr-xr-x 1 root root 1314136 Oct 24 14:34 /usr/sbin/nginx
ana@ubuntu · one program, five processes
ps -C nginx -o pid,user,nlwp,args    PID USER     NLWP COMMAND
     39 root        1 nginx: master process nginx
     40 www-data    1 nginx: worker process
     41 www-data    1 nginx: worker process
     42 www-data    1 nginx: worker process
     43 www-data    1 nginx: worker process

Why two kinds? The master starts as root, so it can open the web port, and then it only manages the workers. The workers do the real work: they answer every request. If someone breaks into a worker, they get www-data's permissions, not root's. As in episode three: give each job only the access it needs.

What a process is: diagram from the video

What a thread is

A thread is a worker inside a process. Every process starts with one. It can start more, and they all share the process's memory: the same data, the same open files. Each thread only keeps its own small notepad, called a stack, and its own place in the code. So threads are teammates in one room, and processes are people in separate rooms.

What a thread is: diagram from the video

That's MariaDB. pidof finds MariaDB's PID, and ps with dash T lists the threads of that one process. They all share one PID, 489, and each has its own thread ID in the S P I D column. Linux also shows every running process as a folder in slash proc, with one entry per thread. Counting them gives ten, the same number as ps.

ana@ubuntu · inside MariaDB
ps -T -p $(pidof mariadbd) | head -5    PID    SPID TTY          TIME CMD
    489     489 ?        00:00:00 mariadbd
    489     491 ?        00:00:00 mariadbd
    489     492 ?        00:00:00 mariadbd
    489     493 ?        00:00:00 mariadbd
ana@ubuntu · inside MariaDB
ls /proc/$(pidof mariadbd)/task | wc -l10

Now Ana's two databases make sense. PostgreSQL has a main process that waits for customers. For each new connection, it starts a new process, and that process serves only that customer. MariaDB stays one process. For each new connection, it starts a new thread inside itself, sharing the database's memory.

What a thread is: diagram from the video

Round 1: Sharing memory

Round one: sharing memory. To test it, we wrote a tiny program called counter. It starts four workers, and each one adds one to a number, a million times. With four processes, each worker has its own copy of the number. With four threads, they all add to the same one.

Round 1: Sharing memory: diagram from the video

Processes first. Each process counted its own copy to a million. The parent, the process that started them, still has zero: nothing was shared. Now threads. Four million expected, and we got about one point nine million. Run it again: about one point four million. A different wrong answer every time.

ana@ubuntu · counter
counter --processes 44 processes, each with its own copy.
process 1: its copy is 1000000
process 2: its copy is 1000000
process 3: its copy is 1000000
process 4: its copy is 1000000
parent:    its copy is 0
ana@ubuntu · counter
counter --threads 44 threads share one number.
expected: 4000000
result:   1903149
ana@ubuntu · counter
counter --threads 44 threads share one number.
expected: 4000000
result:   1371366

Where did the missing adds go? Adding one is three small steps: read the number, add one, write it back. Two threads read five at the same moment. Both write back six. Two adds, but the number only went up by one. This is called a race condition.

Round 1: Sharing memory: diagram from the video

The fix is a lock: only one thread may change the number at a time, and the others wait their turn. With the lock: four million, exactly. It's a little slower, because threads now take turns, but the answer is right.

ana@ubuntu · counter, with a lock
counter --threads 4 --lock4 threads share one number, with a lock.
expected: 4000000
result:   4000000

So threads win at sharing: it's fast and it's built in, but every piece of shared data needs a lock. Processes can't see each other's memory, so they send messages instead. You've already used one way: the pipe. Take ps aux, piped into grep nginx. That's two processes, and the pipe carries the output of the first one into the second. Network sockets do the same between programs, even on different machines.

Round 1: Sharing memory: diagram from the video

Round 2: Crashes

Round two: crashes. A bug that touches memory a program doesn't own is called a segmentation fault. Linux then stops the whole process. Not just the thread with the bug: every thread inside it. Our second program, crash, starts four workers, and worker three has that bug.

Round 2: Crashes: diagram from the video

With threads: worker three hits the bug, and everything is gone. Segmentation fault, and not one worker finished. With processes: worker three dies alone. One, two and four finish, and the parent sees what happened and keeps running.

ana@ubuntu · crash
crash --threads 4starting 4 threads in one process
thread 3: bad memory access!
Segmentation fault (core dumped)
ana@ubuntu · crash
crash --processes 4starting 4 processes
process 3: bad memory access!
process 1: finished
process 2: finished
process 4: finished
parent: process 3 was killed (Segmentation fault)
parent: still running

Real servers use this. Ana stops worker 40 with kill dash nine, the way a crash would end it. ps again: the master already started a new worker, PID 1025. And the website still answers: two hundred, OK.

ana@ubuntu · kill one nginx worker
sudo kill -9 40[sudo] password for ana:
ana@ubuntu · kill one nginx worker
ps -C nginx -o pid,user,nlwp,args    PID USER     NLWP COMMAND
     39 root        1 nginx: master process nginx
     41 www-data    1 nginx: worker process
     42 www-data    1 nginx: worker process
     43 www-data    1 nginx: worker process
   1025 www-data    1 nginx: worker process
ana@ubuntu · kill one nginx worker
curl -sI localhost | head -1HTTP/1.1 200 OK

So processes win this round, and threads lose it: one bad thread stops them all. That's why web browsers like Chrome run websites in separate processes. One broken page can't take down the others, and each one can be locked in a sandbox, a fence around what it may touch. And it's one reason PostgreSQL gives each customer a process of its own.

Round 2: Crashes: diagram from the video

Round 3: Starting one

Round three: the cost of starting one. A new process needs its own memory, so Linux sets up a private copy of the parent's memory for it. It copies only the pages that change, but there's still work to do. A new thread just needs a small stack, in memory that's already there.

Round 3: Starting one: diagram from the video

Our third program, spawn, starts ten thousand workers that do nothing, one after another, and times it. Ten thousand threads: two hundred and ninety-two milliseconds. Ten thousand processes: nine hundred and ninety-four.

ana@ubuntu · spawn
spawn --threads 1000010000 threads started and finished in 292 ms
ana@ubuntu · spawn
spawn --processes 1000010000 processes started and finished in 994 ms

Over six runs each, threads took about two hundred and ninety-two milliseconds, and processes about three times as long. So threads win this round. Each start is still under a tenth of a millisecond, so it matters most when a server starts thousands.

Round 3: Starting one: diagram from the video

Round 4: CPU cores

Round four: CPU cores. A core is one part of the processor that runs one thing at a time, and the server Ana runs has four. Linux's scheduler decides what runs on each core, and it schedules threads, not programs. A process with one thread is one task to it. A process with four threads is four tasks, and they can run on four cores at the same time.

Round 4: CPU cores: diagram from the video

Our last program, burn, keeps four workers busy for a few seconds. As threads: one process, five threads, at three hundred and ninety-seven percent CPU. ps counts a hundred percent per core, so that's four full cores. As processes: four processes at about a hundred percent each, plus the parent, resting at zero.

ana@ubuntu · burn
nproc4
ana@ubuntu · burn
burn --threads 4 & sleep 3; ps -C burn -o pid,nlwp,pcpu,comm; wait[1] 121102
    PID NLWP %CPU COMMAND
 121102    5  397 burn
[1]+  Done                    burn --threads 4
ana@ubuntu · burn
burn --processes 4 & sleep 3; ps -C burn -o pid,nlwp,pcpu,comm; wait[1] 121109
    PID NLWP %CPU COMMAND
 121109    1  0.0 burn
 121111    1  100 burn
 121112    1  100 burn
 121113    1 99.6 burn
 121114    1 99.6 burn
[1]+  Done                    burn --processes 4

So on Linux, this round is a tie: threads and processes both use every core. The five threads are the four workers, plus the main one, which waits for them. One caution: some languages limit threads. In Python, only one thread runs Python code at a time, as we showed in our Python video.

Round 4: CPU cores: diagram from the video

When each one wins

Each design has a known fix for its weak spot. A process per customer costs memory, so busy PostgreSQL servers put a connection pooler in front, like PgBouncer. Thousands of customers share a few dozen database processes. MariaDB can do the opposite: its thread pool lets a few threads serve many customers, so it doesn't need thousands of threads.

When each one wins: diagram from the video

Here's the score. Threads win at sharing memory, as long as you lock what's shared, and at starting fast. Processes win at keeping a crash, or a break-in, inside one process. And both use every core.

When each one wins: diagram from the video

So here's the rule. Use processes when jobs must stay separate: different users, code you don't fully trust, or a crash that must not spread. Use threads when lots of small jobs share the same data. Many real programs use both: Chrome runs a few processes, and each of them has many threads. And for the shop Ana runs, both databases are fine: a few customers are cheap either way.

When each one wins: diagram from the video

Recap

So, a process is a program running, with its own private memory and its own PID. A thread is a worker inside a process, sharing that memory. Threads share easily and start fast, but one crash stops them all. Processes keep each crash, and each user, apart. And on Linux, both use every core.

Which program on your machine has the most threads? Run ps, sorted by thread count, and tell me in the comments.

Sources

Demos: real servers and four small test programs (counter, crash, spawn, burn) on one test machine (an Ubuntu 24.04 container). Watch the full video on YouTube.

More videos