Process Synchronization

Julie Oh·2025년 7월 29일

Operating system

목록 보기
10/14

🔒 Synchronization

: The coordination of multiple threads or processes to ensure they access shared resources in a controlled manner, preventing data corruption and race conditions

🧠 Why Synchronization Matters

  • Synchronization for proper execution order: A process should execute ahead B process
    ex) Write process should finish before Read process
  • Synchronization for mutual exclusion: Prevent multiple processes from accessing shared resources simultaneously
Shared amount = 10
Process A reads amount → adds 2 → writes 12
Process B reads amount → adds 5 → writes 15
If both access at the same time → result may be incorrect

🧩 Key Concepts
Shared Resource: can't be accessed concurrently without synchronization
ex) global variable, files, I/O devices, or secondary memory
Critical Section: code block that accesses or modifies shared resource

⚠️ Problems Without Synchronization
Race condition**: Occurs when two or more processes access the critical section simultaneously, causing unpredictable or incorrect results

🧮 How Race Conditions Happen
High-level operations are translated into machine codes(instructions)
ex) "Increment a by 1"

r1 = a // store a into register
r1 = r1 + 1 // increment register
a = r1 // store register into variable

If a context switching occurs between these steps, it may corrupt the result.

Conditions for Proper Synchronization (Mutual Exclusion)
1. Mutual exclusion: only one process may be in critical section at a time
2. Progress: if no process is in the critical section, the next eligible proces should be allowed to enter without unnecessary delay
3. Bounded waiting: A process waiting to enter critical section will eventually get its turn

🔧 Synchronization Methods

1. Mutex Lock — for mutual exclusion
it is like a lock in one changing room

  • Global variable lock
  • Acquire: lock the critical section
  • Release: unlock the critical section
bool lock = false;

acquire() {
	while (lock == true) {// if it is locked
    // keep checking whether it is locked still
}
// if it is not locked, lock it
lock = true;
}

release() {
	lock = false // unlock it after get out of critical section
}
acquire() // check whether it is locked, if it not, lock it 
{enter the critical section}
release() // unlock it

Busy waiting wastes CPU cycles while contantly checking the lock

**2. Semaphore — for managing multiple resource units

  • Global variable S: the number of available shared resources
  • Wait: control to enter the critical section
  • Signal: Release a resource to let other processes enter into the critical section

a. with busy waiting

wait() {
	while(S <= 0) // if there is no available resources 
    {
    // keep checking whether any resources are available
    } 
    S--; // Use that resource and enter the critical section
}

signal() {
	S++; // After critical section, release S
}

=> Busy waiting wastes CPU

b. without busy waiting, use a waiting queue (a block queue)

wait() {
	S--;
	while(S < 0) // if there is no available resources 
    {
    Add this process to Queue;
    sleep(); // process is in a waiting queue
    } 
}

signal() {
	S++; // After critical section, release S
    if (S <= 0) {
    	remove a proess p from a waiting queue
        wakeup(p) // move p to ready queue
    ]
}

Both usage is the same

wait()
{Enter the critical section}
signal()

🔁 Synchronization for Execution Order

3. Monitor — combines mutual exclusion and condition variables

Think of it as a manager for accessing shared resources through defined interfaces.
shared resource (e.g., a file, printer, buffer)
interfaces (methods) — like read(), write(), access(), etc.

🔐 Mutual Exclusion
a. Only one process can enter the monitor(critical section) at a time
b. Other processes wait in the monitor entry queue

🧭 Condition Variables (for execution order)
--> x.wait()
: process gives up the monitor and waits on condition x
--> x.signal()

  • another process signals that the condition has been met(e.g. I just put something in the buffer)
  • This wakes up one process waiting on x, moving it to the monitor's entry queue
monitor Buffer {
    condition notEmpty;

    void consume() {
        if (buffer is empty) {
            notEmpty.wait(); // ❗ Wait until producer adds something
        }
        // Consume item
    }

    void produce(item) {
        // Add item to buffer
        notEmpty.signal(); // ✅ Notify consumer that item is available
    }
}

A condition variable is a special object used for:
Putting a process to sleep (wait())
Waking up a sleeping process (signal())

0개의 댓글