CSOPESY_synchronization_tools

Announcements

Synchronization Tools

Background and the Critical-Section Problem

this might not be copied properly

// g++ critical_sec.cpp -o critical_sec.exe
#include <iostream>
#include <thread>
#include <mutex>
#include <random>
#include <chrono>

// a mutex to protect the shared 'count' variable and
// ensure that the output is not jumbled
std::mutex mtx;

// global variable to be incremented by multiple threads
int counter = 0;

// this is the function that each thread will execute
// it takes an integer 'id' to identify the thread
void print_numbers(int id, int iteration) {
	thread_local std::mt19937 generatorrandom_device{}() + id;
	std::uniform_int_distribution<int> distribution (1, 1000);
	
	for (int i=0; (i < iteration); i++) {
		int local_count;
		//lock the mutex to ensure exclusive access to the shared resources
		// std::unique_lock<std::mutex> lock(mtx);
		// mtx.lock();
		std::cout << "Thread " << id << ": " << counter << std::endl;
		// THIS IS THE START OF THE CRITICAL SECTION !!!!!!!!!!!!!!
		local_count = counter;
		local_count++; // equivalent to local_count = local_count+1;
		// machine code equivalent is 
		// load register, local_count
		// add register, 1
		// store local_count, register 
		int random_num = distribution(generator);
		std::this_thread::sleep_formilliseconds(random_num);
	}
	
	// unlock the mutex when the scope ends
	// mtx.unlock();
	// THIS IS THE END OF THE CRITICAL SECTION !!!!!!!!!!!!!!
	std::this_thread::sleep_formilliseconds(100);
}

int main() {
	// create two threads, passing the print_numbers function
	// and a unique ID for each thread
	
	std::cout << "Initial value of counter is " << counter << std::endl;

	std::thread thread1(print_numbers, 1, 20);
	std::thread thread2(print_numbers, 2, 20);
	
	// wait for both threads to finish their execution
	thread1.join();
	thread2.join();
	
    std::cout << "all threads have finished" << std::endl;
    std::cout << "Final value of counter is " << counter << std::endl;
    return 0;
}

The Critical-Section Problem (Solution Requirements - So what do you do?)

any solution to the critical-section problem must satisfy three requirements

Peterson's Solution

A classic software-based solution to the critical -section problem for two processes and

The Protocol for Process:

do {
	flag[i] = true; // indicate i want to enter
	turn = j; // give permission to the other process
	while (flag[j] && turn == j);
	// wait if other process wants in AND its their turn
	// CRITICAL SECTION
	flag[i] = false; // exit
	// REMAINDER SECTION
} while (true);

The solution...

sample trace in slides

Synchronization Hardware

some high-level code/not machine code

boolean TestAndSet(boolean *target) {
	booleanrv = *target;
	*target = true;
	return rv;
}

boolean CompareAndSwap(int *value, int expected, int new_value) {
	int temp = *value;
	if (*value == expected) { *value = new_value }
	return temp;
}

Mutex Locks

code edit at 52:10

Semaphores

a synchronization primitive that provides a more sophisticated tool than simple mutex locks (a mutex lock but you can put a number on it)

Classic Synchronization Problems

used as benchmarks to test the efficiency and correctness of new synchronization tools:

Bounded-Buffer Problem (Producer-Consumer)

Semaphores used:

Readers-Writers Problem

Monitors

a high-level synchronization construct that is designed to simplify concurrent programming and avoid common errors associated with semaphores

Deadlocks and Starvation