# Lecture 004 - Concurrency

## Classical Concurrency

Goal for multiple node concurrency is to mitigate one node's failure

Critical Section: piece of code accessing a shared resource, usually variables or data structures

Race Condition: Multiple threads of execution enter CS at the same time, update shared resource, leading to undesirable outcome

Indeterminate Program: One or more Race Conditions, output of program depending on ordering, non deterministic

Mutual Exclusion: guarantee that only a single thread/process enters a CS, avoiding races

• Correctness: single process at critical section

• Efficiency: no spin-locks

• Fairness: no process wait for ever

Mutual Exclusion: Atomic setting and testing implemented by hardware.

Semaphores: shared address space with integer variable with increase and decrease operations.

Note that binary semaphores is logically identical with mutex.

Condition Variables (cvars): thread suspended until activated by other threads (more efficient than spin lock)

cvar.Wait():
Must be called after locking mutex.
Atomically: release mutex & suspend operation
When resume, lock mutex (but maybe not right away)
cvar.Signal():
If no thread suspended, then NO-OP
Wake up (at least) one suspended thread.
(Typically do within scope of mutex, but not required)


Resume isn't safe since it may not lock mutex right away... so you end up with a while loop to recheck condition.

Mesa semantics (looser) vs Hoare Semantics (tighter)

## Concurrency Model in Golang

There are channels and goroutines.

• channel: communicate between goroutine

• goroutine: independently execute functions (independent call stack, but inexpensive)

The idea is instead of communicating with shared memory, we simulate shared memory by communication.

When channel capacity is $0$, it becomes a synchronization point. You can only send to a chanel of capacity $0$ if and only if there exist processes currently listening.

Note that if you are running in one core, $0$ capacity channel might have logical deadlock, but I believe golang will work it out.

Note that there isn't really reason to use channel size other than $0$ or $1$. Big channel size might hide concurrency bugs.

You can use channels to implement mutex.

Limitation to channels:

• bounded channel size buffer

• no way to test for emptiness

• you cannot put back values to head of channel

• cannot flush channel

• cannot peak channel

Q: How do you change a lightbulb in concurrent programming?

A. You take the lamp to a secure area so nobody else can try to change the lightbulb while you're changing it. Alternatively, you might get a lamp with lightbulbs that can't be changed, and just get a new lamp when the lightbulb goes out.

Table of Content