Sesi 6 Sinkronisasi Proses Materi Latar Belakang Masalah
Sesi 6. Sinkronisasi Proses
Materi • • • Latar Belakang Masalah Critical Section Problem Peterson's Solution Sinkronisasi dengan Hardware Mutex Semaphore Problem Klasik Sinkronisasi Monitor Contoh pada Sistem Operasi Solusi Alternatif
Latar Belakang Masalah
Latar belakang • Proses-proses yang konkuren adalah proses-proses (lebih dari satu) berada pada saat yang sama. Proses-proses ini dapat sepenuhnya tak bergantung dengan yang lainnya, tapi dapat juga saling berinteraksi. Proses-proses yang berinteraksi memerlukan sinkronisasi agar terkendali dengan baik. • Proses-proses yang melakukan akses secara konkuren pada data yang digunakan bersama-sama menyebabkan data tidak konsisten (inconsistence). Agar data konsisten dibutuhkan mekanisme untuk menjamin eksekusi yang berurutan pada proses yang bekerja sama.
Latar Belakang • Masalah : Akses yang konkuren pada shared data kemungkinan menghasilkan inkonsistensi • Pada model shared memory untuk penyelesaian permasalahan bounded-buffer paling banyak menyimpan n – 1 item pada buffer pada saat yang bersamaan. Untuk mendapatkan solusi dimana semua N buffer digunakan bukan masalah yang sederhana. • Misalnya dilakukan modifikasi kode producer consumer dengan menambahkan variabel counter yang diinisialisasi 0 dan dinaikkan setiap satu item baru ditambahkan ke buffer.
• Definisi data yang digunakan bersama (shared data) adalah sebagai berikut : #define BUFFER_SIZE 10 typedef struct {. . . } item; item buffer[BUFFER_SIZE]; int in = 0; int out = 0; int counter = 0;
• Proses pada producer akan menambahkan satu nilai variabel counter sebagai berikut : item next. Produced; while (1) { while (counter == BUFFER_SIZE) ; /* do nothing */ buffer[in] = next. Produced; in = (in + 1) % BUFFER_SIZE; counter++; }
• Sebaliknya juga proses pada consumer akan menurunkan satu nilai variabel counter sebagai berikut : item next. Consumed; while (1) { while (counter == 0) ; /* do nothing */ next. Consumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; }
Producer Consumer Shared Data counter : variabel pencatat jumlah data sekarang buffer[] : penampung data BUFFER_SIZE : jumlah maksimal buffer Producer(P) while (true) { // Jika yg diproduksi = batas, do nothing while (counter == BUFFER_SIZE); // Produksi data dan masukkan buffer [in] = next. Produced; in = (in + 1) % BUFFER_SIZE; // Tambah counter dengan 1 counter++; } Consumer(C) while (true) { // Jika yang dikonsumsi = 0, do nothing while (counter == 0); // Konsumsi data next. Consumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; // Kurangi counter dengan 1 counter--; } Q : Jika counter = 5, berapa nilai counter setelah satu kali iterasi secara concurrent ?
• Pernyataan counter++ dan counter-- harus dilakukan secara atomik. • Operasi atomik adalah operasi yang harus menyelesaikan seluruh pernyataannya tanpa interupsi. • Pernyataan counter++ akan diimplementasi kan dalam bahasa mesin sebagai berikut :
Nilai Counter • counter++ dapat diimplementasikan dalam bahasa mesin sbb : – register 1 = counter – register 1 = register 1 + 1 – counter = register 1 • counter-- dapat diimplementasikan dalam bahasa mesin sbb : – register 2 = counter – register 2 = register 2 - 1 – count = register 2
• Apabila baik producer dan consumer mencoba mengubah buffer secara konkuren, pernyataan dalam bahasa mesin diatas akan dilakukan secara terpisah. • Misalnya counter diinisialisasi 5. Pernyataan yang dijalankan adalah : producer: register 1 = counter (register 1 = 5) producer: register 1 = register 1 + 1 (register 1 = 6) consumer: register 2 = counter (register 2 = 5) consumer: register 2 = register 2 – 1 (register 2 = 4) producer: counter = register 1 (counter = 6) consumer: counter = register 2 (counter = 4) Nilai counter kemungkinan bernilai 4 atau 6, hal ini yang dimaksud dengan data yang tidak konsisten.
• Situasi dimana beberapa proses mengakses dan memanipulasi data yang digunakan bersama secara konkuren disebut dengan race condition. • Nilai akhir dari data yang digunakan bersama tersebut tergantung dari proses yang terakhir selesai. Untuk mencegah race condition tersebut, proses yang konkuren harus dilakukan sinkronisasi.
Critical Section Problem
CSP • Suatu system terdiri dari n proses dimana semuanya berkompetisi menggunakan data yang digunakan bersama. Masing-masing proses mempunyai sebuah kode segmen yang disebut dengan critical section, dimana proses memungkinkan untuk mengubah variabel umum, mengubah sebuah tabel, menulis file dan lain sebagainya. • Gambaran penting dari sistem adalah, ketika sebuah proses dijalankan di dalam critical section, tidak ada proses lain yang diijinkan untuk menjalankan critical section-nya. • Sehingga eksekusi dari critical section oleh proses-proses tersebut berlaku eksklusif (mutually exclusive).
• Permasalahan critical section digunakan untuk mendesain sebuah protokol dimana proses-proses dapat bekerja sama. Masing-masing proses harus meminta ijin untuk memasuki critical section-nya. • Daerah kode yang mengimplementasikan perintah ini disebut daerah entry. Critical section biasanya diikuti oleh daerah exit. Kode pengingat terletak di daerah remainder. • Sebuah solusi dari permasalahan critical section harus memenuhi 3 syarat sebagai berikut :
Solusi Critical Section Problem • Mutual Exclusion. Jika proses P i mengekseskusi critical section nya, maka tidak ada proses lain yang dapat mengeksekusi critical section nya. • Progress. Jika tidak ada proses yang mengeksekusi critical section nya dan terdapat beberapa proses yang akan memasuki critical section, maka pemilihan proses yang akan memasuki critical section berikutnya tidak dapat ditunda tanpa batas • Bounded Waiting. Ada batasan waktu tunggu ketika proses diizinkan untuk memasuki critical section setelah proses membuat permintaan untuk memasuki critical section dan sebelum permintaan yang diberikan. – Diasumsikan setiap proses dieksekusi dengan kecepatan lebih dari 0 – Tidak ada asumsi mengenai kecepatan relatif proses n
Peterson's Solution
Peterson's Solution • Solusi sederhana sinkronisasi dua process – Contoh : Process Pi dan Pj • Asumsi : instruksi LOAD dan STORE bersifat atomik (tidak bisa diinterupsi) • Dua process berbagi variabel : – int turn – Array boolean flag[2] • Variabel turn menunjukkan process mana yang masuk critical section • Array flag menunjukkan bahwa sebuah process siap mengeksekusi critical section. – flag[i] = true menunjukkan process Pi siap
• Algoritma 1 • Pendekatan pertama adalah memperbolehkan semua proses menggunakan variable integer turn diinisialisasi ke 0 (atau 1). int turn; Apabila turn = i, maka proses Pi diijinkan untuk menjalankan critical section – nya. Struktur dari proses Pi adalah sebagai berikut :
do { while (turn != i) ; critical section turn = j; reminder section } while (1); • Pemecahan ini menjamin hanya satu proses pada satu waktu yang dapat berada di critical section. Tetapi hal ini tidak memuaskan kebutuhan progress, karena hal ini membutuhkan proses lain yang tepat pada eksekusi dari critical section. • Sebagai contoh, apabila turn=0 dan P 1 siap untuk memasuki critical section, P 1 tidak dapat melakukannya, meskipun P 0 mungkin di dalam remainder section – nya.
Algoritma 2 • Kelemahan dengan algoritma 1 adalah tidak adanya informasi yang cukup tentang state dari masing-masing proses. Untuk mengatasi masalah ini dilakukan penggantian variabel turn dengan array boolean flag[2]; • Inisialisasi awal flag [0] = flag [1] = false. Apabila flag[i] bernilai true, nilai ini menandakan bahwa Pi siap untukmemasuki critical section. struktur dari proses Pi adalah sebagai berikut : do { flag[i] : = true; while (flag[j]) ; critical section flag [i] = false; remainder section } while (1); • Pemecahan ini menjamin mutual exclusion, tetapi masih belum memenuhi progress.
Peterson's Solution untuk Process Pi do { // Process Pi siap eksekusi, ganti giliran eksekusi ke Pj flag[i] = TRUE; turn = j; // Jika giliran Pj eksekusi critical section, Pi Do Nothing while (flag[j] && turn == j); critical section Pi flag[i] = FALSE; remainder section Pj } while (TRUE); • Memenuhi 3 syarat : – Mutual exclusion – Progress – Bounded waiting
Algoritma 3 • Algoritma ini merupakan kombinasi algoritma 1 dan algoritma 2. Harapannya akan didapatkan solusi yang benar untuk masalah critical-section, dimana proses ini menggunakan dua variabel : int turn; boolean flag[2]; • Inisialisasi flag. I[0] = flag[1] = false dan nilai dari turn bernilai 0 atau 1. • Struktur dari proses Pi adalah :
do { flag [i]: = true; turn = j; while (flag [j] and turn = j) ; critical section flag [i] = false; remainder section } while (1); • Algoritma ketiga ini memenuhi ketiga kebutuhan diatas yaitu mutual exclusion, progress dan bounded waiting dan memecahkan permasalahan critical section untuk dua proses
Sinkronisasi dengan Hardware
Sinkronisasi dengan Hardware • Banyak sistem menyediakan dukungan hardware untuk menangani critical section code • Melakukan locking : memproteksi critical section dengan lock. • Pada single-processor – Disable interrupt – Code yang sedang dieksekusi tidak akan mengalami preemption – TIDAK efisien untuk multiprocessor : pesan akan disebar ke semua processor • Modern-computer – Menyediakan instruksi hardware khusus yang atomik (tidak bisa diiterupsi) – Dua pendekatan : • Test and set • Swap content of two memory words
Solusi Critical Section dengan Locking do { acquire lock critical section release lock remainder section } while (TRUE);
Solusi Critical Section dengan Test. And. Set • Shared boolean variable lock, initialized to FALSE • � Solution: do { // Do nothing jika lock = true while ( Test. And. Set (&lock )); critical section lock = FALSE; // reset lock to false remainder section } while (TRUE); boolean Test. And. Set (boolean *lock) { boolean rv = *lock; // set lock = TRUE, lock the execution *lock = TRUE; // return previous lock status return rv: }
Instruksi Test. And. Set • Definisi: boolean Test. And. Set (boolean *lock) { boolean rv = *lock; // set lock = TRUE, means lock the execution *lock = TRUE; // return previous lock status return rv: } • Misal ada process Pi dan Pj • Pi panggil Test. And. Set saat parameter lock = False – Return value = False, process Pi bisa akses critical section-nya – Pj tidak bisa akses critical sectionnya karena lock=True oleh Pi • Pi panggil Test. And. Set saat parameter lock = True – Return value = True, process Pi tidak bisa akses critical section-nya (Do Nothing) – Pi tidak bisa akses critical sectionnya karena sebelumnya lock=True oleh Pj
Solusi Critical Section dengan Swap • Shared Boolean variable lock initialized to FALSE; • Setiap process punya local variable key • �Solution: do { key = TRUE; while ( key == TRUE) Swap (&lock, &key ); // critical section lock = FALSE; void Swap (boolean *lock, boolean *key) // remainder section { } while (TRUE); boolean temp = *lock; // Swap content *lock = *key; *key = temp; }
Instruksi Swap • Definisi: void Swap (boolean *lock, boolean *key) { boolean temp = *lock; // Swap content *lock = *key; *key = temp; } • Misal ada process Pi dan Pj • Pi panggil Swap saat parameter lock = False, key=True – key = False, process Pi bisa akses critical section-nya – Pj tidak bisa akses critical sectionnya karena lock=True oleh Pi • Pi panggil Swap saat parameter lock = True, key=True, – key = True, process Pi tidak bisa akses critical section-nya (Do Nothing) – Pi tidak bisa akses critical sectionnya karena sebelumnya lock=True oleh Pj
Bounded-waiting Mutual Exclusion with Testand. Set() do { waiting[i] = true; key = true; while (waiting[i] && key) key = test and set(&lock); waiting[i] = false; /* critical section */ j = (i + 1) % n; while ((j != i) && !waiting[j]) j = (j + 1) % n; if (j == i) lock = false; else waiting[j] = false; /* remainder section */ } while (true);
Mutex Locks
Mutex Lock • Sinkronisasi dengan hardware terlalu kompleks bagi programmer • Desainer OS menyediakan software tool untuk critical-section problem • Tools paling sederhana adalah mutex (mutually exclusion) • Mutex lock biasanya diimplementasi dengan salah satu mekanisme sinkronisasi dengan hardware • Mutex menyediakan 2 fungsi dasar : – acquire lock : mengunci critical section – release lock : melepas kunci
• Acquire dan release menggunakan shared variable available • Acquire lock acquire() { while (!available); /* busy wait */ available = false; } • Release lock release() { available = true; } • Solusi dengan mutex do { acquire lock critical section release lock remainder section } while (true);
Question • Apa kelemahan mutex dan sinkronisasi dengan hardware?
Answer • Apa kelemahan mutex dan sinkronisasi dengan hardware? – Pada saat suatu critical section di lock oleh satu process, maka proses lain melakukan busy waiting. – Busy waiting : menunggu dengan cara looping terus menerus sampai lock-nya dilepas. • Disebut juga dengan spinlock karena proses lain melakukan "berputar" ketika menunggu – Busy waiting menghabiskan siklus pemrosesan CPU yang seharusnya bisa dimanfaatkan secara produktif oleh proses lain.
Semaphore
Semaphore • Perangkat sinkronisasi yang tidak memerlukan busy waiting. • Semaphore S – shared integer variable • S hanya bisa diakses dengan 2 operasi atomik : wait dan signal • wait : cek S dan mengurangi S dengan 1 wait (S) { while S <= 0; // no-op S--; } • signal : menambah S dengan 1 signal (S) { S++; }
Dua Jenis Semaphore • Counting semaphore – nilai integer S dapat berkisar melalui domain tak terbatas. – Biasanya nilai S diinisiasi sebanyak resource yang dibagi – Jika S=0, maka semua resource sedang dipakai • Binary semaphore – nilai integer S dapat mempunyai jangkauan 0 atau 1 – Lebih sederhana untuk diimplementasikan
Critical Section dengan Semaphore • Shared data: semaphore S; //diinisialisasi S = 1 • Process Pi: do { wait(S); critical section signal(S); remainder section } while (1);
Implementasi Semaphore • Untuk menghindari busy waiting, process yang menunggu akses critical-section harus dihentikan sementara. • Ada dua operasi sederhana yang terlibat : – block : menghentikan sementara (suspend) proses yang memanggil – wakeup(P) : melanjutkan (resume) eksekusi dari proses P yang di-blok • Semaphore tanpa busy waiting butuh struktur data untuk menyimpan process yang sedang suspend. typedef struct { int value; struct process *Q; } semaphore;
Implementasi Semaphore do { wait(S); critical section signal(S); remainder section } while (1); • Operasi Semaphore didefinisikan wait(S){ if (S. value <= 0) { Tambah proses ke queue S. Q; block(); } else{ S. value--; } } signal(S){ if (S. value <= 0) { Hapus proses P dari queue S. Q; wakeup(P); } S. value++; }
Masalah : Deadlock dan Starvation • Deadlock – dua atau lebih proses menunggu tanpa kepastian suatu event yang dapat disebabkan oleh satu proses yang sedang menunggu. • Misalnya S dan Q adalah 2 semaphores yang diinisialisasi 1 • Starvation : blocking terus menerus Sebuah proses mungkin tidak pernah dihapus dari antrian semaphore yang dihentikan sementara (suspend)
Permasalahan Klasik pada Sinkronisasi
Permasalahan Klasik pada Sinkronisasi • Ada beberapa permasalahan klasik dalam sinkronisasi – Permasalahan Bounded-Buffer – Permasalahan Readers and Writers – Permasalahan Dining-Philosophers
Permasalahan Bounded-Buffer • N buffers, each can hold one item • Shared data semaphore full, empty, mutex; • Inisialisasi: full = 0, empty = n, mutex = 1
Bounded Buffer untuk Producer do {. . . memproduksi item nextp. . . wait(empty); wait(mutex); . . . tambahkan nextp ke buffer. . . signal(mutex); signal(full); } while (1);
Bounded Buffer untuk Consumer do { . . . wait(empty); wait(mutex); . . . mengambil item dari buffer ke nextc. . . signal(mutex); signal(full); . . . mengkonsumsi item pada nextc. . . } while (1);
Permasalahan Readers-Writers • Sebuah dataset di-share untuk beberapa proses yang konkuren – Readers : hanya membaca dataset – Writers : membaca • Masalah – Ijinkan banyak reader untuk membaca dalam waktu bersamaan – Ijinkan hanya satu writer mengakses dalam satu waktu • Shared data – – Data set Semaphore mutex initialized to 1 Semaphore wrt initialized to 1 Integer readcount initialized to 0
Proses Writers do { wait (wrt) ; //writing is performed signal (wrt) ; } while (TRUE);
Proses Readers do { wait (mutex) ; readcount ++ ; if (readcount == 1) wait (wrt) ; signal (mutex). . . // reading is performed. . . wait (mutex) ; readcount - - ; if (readcount == 0) signal (wrt) ; signal (mutex) ; } while (TRUE);
Permasalahan Dining-Philosophers • Filosofer menghabiskan hidupnya hanya untuk makan dan berpikir • Tidak ada interaksi dengan sebelahnya • Setiap filosofer mencoba mengambil 2 chopstick untuk makan nasi dari mangkok – Butuh 2 chopstick untuk makan • Shared data – Bowl of rice (data set) – Semaphore chopstick [5] initialized to 1
Filosofer i do { wait ( chopstick[i] ); wait ( chop. Stick[ (i + 1) % 5] ); // Makan signal ( chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // Berpikir } while (TRUE);
Monitor
Monitor • Baca textbook section 5. 8 chapter 5
Sinkronisasi pada Beberapa OS
Sinkronisasi pada Linux • Linux: – Prior to kernel Version 2. 6, disables interrupts to implement short critical sections – Version 2. 6 and later, fully preemptive • Linux provides: – semaphores – spinlocks – reader-writer versions of both • On single-cpu system, spinlocks replaced by enabling and disabling kernel preemption
Sinkronisasi pada Solaris • Mengimplementasikan beberapa lock kunci untuk mendukung multitasking, multithreading (termasuk thread real-time), dan multiprocessing. • Menggunakan adaptive mutexes untuk efisiensi ketika melindungi data dari segmen kode pendek • Menggunakan condition variables dan readers-writers locks ketika segmen kode panjang memerlukan akses ke data. • Menggunakan turnstiles untuk memesan daftar thread menunggu untuk memperoleh adaptive mutexes atau readers -writers locks
Sinkronisasi Windows 2000 • Menggunakan interrupt mask untuk melindungi akses ke sumber daya global pada sistem prosesor tunggal. • Menggunakan spinlocks pada sistem multiprosessor • Juga menyediakan dispatcher object yang dapat bertindak sebagai mutex dan semaphore. • Dispatcher object juga dapat menyediakan event. Event bertindak seperti sebuah variabel kondisi.
Pendekatan Alternatif
Pendekatan Alternatif • Baca textbook section 5. 10 chapter 5
- Slides: 63