---
type: theoretical
backlinks:
  - "[[Overview#Multiprogramming]]"
---

## Intro
Processes frequently need to communicate with other
processes.

### Independent
Cannot affect or be affected by other processes.

### Dependent
The opposite

### Why?
- Information sharing
- Computation speedup
- Modularity
- Convenience

## Methods
### Shared memory
```mermaid
block-beta
  columns 1
	a["Process A"] Shared b["Process B"] ... Kernel

```

Processes/threads exchange information by writing in shared memory variables. This is where [Concurrency](Inter-Process%20Communication.md#Concurrency) becomes an issue.
#### Synchronization
To remedy the race condition issue, we should synchronize shared memory access. In other words, **when a process writes to shared memory, others mustn't be able to**. Multiple read access is allowed though.
### Message passing (queueing)
```mermaid
block-beta
  columns 1
	a["Process A"] b["Process B"] ... ... Kernel

```

Processes communicate with each other by exchanging messages. A process may send information to a port, from which another process may receive information.
We need to at least be able to `send()` and `receive()`.
## Concurrency
Accessing the same shared memory might at the same time will cause issues. This occurrence is called a **Race Condition**.

> [!IMPORTANT]- When does it occur? 
> A race condition occurs when some processes or threads can access (read or write) a shared data variable concurrently and at least one of the accesses is a write access (data manipulation).

The result depends on when context switching[^1] happens.

The part of the program where shared memory is accessed is called the **Critical Section (CS)**.

### Critical Regions/Sections
![|600](Pasted%20image%2020250502174340.png)

### Avoiding race conditions

> [!IMPORTANT]- Conditions
>1. No two processes may be simultaneously inside their critical regions. (Mutual Exclusion)
>2. No assumptions may be made about speeds or the number of CPUs.
>3. No process running outside its critical region may block other processes.
>4. No process should have to wait forever to enter its critical region. (Starvation)
### Locks
A flag which tells us whether the shared memory is currently being written into.

### Mutexes
Mutual exclusion - a type of **lock**, specifically to enforce point 1 in [Avoiding race conditions](Inter-Process%20Communication.md#Avoiding%20race%20conditions) (i.e. enforcing mutual exclusion).

### Semaphores
Can alllow more than one thread to access a resource. Based on amount of permits. Could be a binary one, which is essentially just a lock, otherwise is called a counting semaphore, only allowing as much writes as implemented. 

Use a `wait()`
```c
void wait(int *S){  
	while((*S)<=0);   // busy waiting  
	(*S)--;  
}

```
and a `signal()`:
```c
void signal(int *S){  
	(*S)++;  
}
```
Just keep a fucking list of processes currently semaphoring.
#### Producer-Consumer Problem
- The producer produces items and places them in the buffer.  
- The consumer removes items from the buffer for processing
We need to ensure that when a producer is placing an item in the buffer, then at the same time consumer should not consume any item. In this problem, the buffer is the **critical section**.

> [!example]- How do we solve this?
> To solve this problem, we need two counting semaphores – Full and Empty. “Full” keeps track of some items in the buffer at any given time and “Empty” keeps track of many unoccupied slots.

#### Readers-Writers Problem
* Multiple readers can access the shared data simultaneously without causing any issues because they are only reading and not modifying the data.
* Only one writer can access the shared data at a time to ensure data integrity

We already mentioned this in[Synchronization](Inter-Process%20Communication.md#Synchronization)

> [!example]- How do we solve this?
> Two solutions. We either give priority to readers or writers, but we have to do so consistently. This  means that we let read/write happen first until exhaustion.
### Peterson's Algorithm

Where `i` and `j` are separate processes.

1. Two Boolean flags: one for each process (e.g.,`flag[0]` and `flag[1]`). Each flag indicates whether the corresponding process wants to enter the critical section.
2. 
```c
flag[i] = true;
turn = j;
while (flag[j] && turn == j) {
    // busy wait[^2]
}
```
3. Once the while loop condition fails, process i enters its critical section.
4. After finishing its critical section, process i sets flag[i] to false.
5. Repeat!



## Monitors
A high-level abstraction that provides a convenient and effective mechanism for process synchronization.
It defines procedures (i.e. methods).

> [!WARNING]
> Only one process may be executing any of the monitor's procedures at a time within the monitor at a time

It uses **condition variables** (often with wait and signal[^3]operations) to allow threads to wait for certain conditions to be met before proceeding.

![|600](Pasted%20image%2020250502180811.png)


## Endianness
![](Pasted%20image%2020250505163335.png)

---

[^1]: [Context switching](Processes%20and%20Threads.md#Context%20switching)
[^2]: Process repeatedly checks a condition (usually in a loop) until a desired event or state is reached. Not too different from polling.
[^3]: to the other threads
