No history yet

Introduction to Concurrency

What is Concurrency?

Think about two chefs working in the same kitchen. If one is chopping vegetables while the other is boiling water, they can both make progress on their tasks at the same time. They don't have to wait for each other to finish. This is the core idea behind concurrency in computing.

Concurrency

noun

The ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome.

A computer system uses concurrency to run multiple processes or smaller units called threads simultaneously. Instead of running one task from start to finish before beginning the next, the system juggles them, switching back and forth so rapidly that they appear to be running at the same time. This is especially useful for making applications feel responsive. For example, a web browser can download a large file in one thread while you continue to browse other websites in another.

The Trouble with Sharing

Our kitchen analogy works well until both chefs need the same salt shaker at the exact same moment. This is the fundamental challenge of concurrency: managing access to shared resources. In computing, a shared resource could be a piece of memory, a database entry, or a file on a disk.

When multiple threads try to read and write to the same shared resource without any coordination, chaos can ensue. The final outcome becomes unpredictable and depends on the precise, often random, order in which the threads execute. This problem is known as a race condition.

A race condition occurs when the behavior of a system depends on the sequence or timing of uncontrollable events. It becomes a bug when events do not occur in the order the programmer intended.

Let's look at a simple example. Imagine two threads are trying to update a shared bank account balance. The initial balance is $100. Thread 1 wants to deposit $50, and Thread 2 wants to withdraw $20. The final balance should be $130.

// Initial Balance = 100

// --- Thread 1 (Deposit 50) ---
1. Read balance (100)
2. Add 50 (100 + 50 = 150)
3. Write new balance (150)

// --- Thread 2 (Withdraw 20) ---
1. Read balance (100)
2. Subtract 20 (100 - 20 = 80)
3. Write new balance (80)

If these threads run one after the other, everything is fine. But what if the operating system interleaves their steps like this?

StepThread 1 ActionThread 2 ActionBalanceNotes
1Reads balance (100)100Thread 1 has a local copy of 100.
2Reads balance (100)100Thread 2 also has a local copy of 100.
3Adds 50 to its copy (150)100Balance in memory is still 100.
4Subtracts 20 from its copy (80)100Both threads work on outdated info.
5Writes 150 to balance150Thread 1's work is saved.
6Writes 80 to balance80Thread 2 overwrites Thread 1's update!

The final balance is $80. The $50 deposit was completely lost. This is a classic race condition that leads to data inconsistency.

The Need for a System

To prevent these kinds of errors, we need rules for accessing shared resources. We need a way to ensure that when one thread is performing a critical operation, like updating a bank balance, no other thread can interfere until it's finished. This process of coordinating access is called synchronization.

Synchronization mechanisms are like traffic signals for threads. They establish order and prevent collisions. By carefully controlling which thread gets to use a shared resource and when, we can harness the power of concurrency without falling victim to its pitfalls.

Understanding these foundational concepts is the first step toward building robust, multi-threaded applications. Without proper synchronization, concurrent programs are unreliable and can produce incorrect results in subtle and hard-to-debug ways.

Quiz Questions 1/5

What is the primary goal of concurrency in a computer system?

Quiz Questions 2/5

A race condition occurs when multiple threads access a shared resource, and the final result depends on the unpredictable order of their execution.