Giải pháp cho Vấn đề Critical Section - ndtien-practice-c

Download Report

Transcript Giải pháp cho Vấn đề Critical Section - ndtien-practice-c

Chương 6: Đồng bộ hóa tiến
trình
Nguyên lý hệ điều hành
Nguyễn Đức Thịnh - ĐHNNHN
Nội dung
 Kiến thức nền
 Vấn đề về Critical Section
 Lời giải của Peterson
 Phần cứng đồng bộ hóa
 Semaphore
 Các vấn đề cổ điển của đồng bộ hóa
 Monitor
 Các ví dụ
 Giao tác nguyên tố (Atomic Transactions)
Nguyên lý hệ điều hành
6.2
Nguyễn Đức Thịnh - ĐHNNHN
Mục tiêu
 Vấn đề critical-section, các giải pháp được dùng để đảm bảo tính nhất
quán của dữ liệu chia sẻ
 Trình bày giải pháp phần cứng và phần mềm của critical section
problem
 Giới thiệu khái niệm về atomic transaction và trình bày cơ chế để đảm
bảo tính nguyên tố (atomicity)
Nguyên lý hệ điều hành
6.3
Nguyễn Đức Thịnh - ĐHNNHN
Kiến thức nền
 Truy cập đồng thời tới dữ liệu chia sẻ có thể gây ra sự không nhất
quán
 Duy trì sự nhất quán dữ liệu cho ta cơ chế để đảm bảo sự thực thi có
trật tự của các tiến trình tương tác
 Giả sử rằng chúng ta muốn cung cấp một giải pháp cho vấn đề
consumer-producer làm đầy các bộ đệm (buffer). Ta có thể làm vậy
bằng cách dùng một bộ đếm (counter) theo dõi số lượng các item
trong buffer. Ban đầu, count được đặt bằng 0. Nó được tăng lên bởi
producer sau khi nó tạo ra một item mới và được giảm đi bởi
consumer sau khi nó tiêu thụ một item.
Nguyên lý hệ điều hành
6.4
Nguyễn Đức Thịnh - ĐHNNHN
Producer
while (true) {
/* produce an item and put in nextProduced */
while (count == BUFFER_SIZE)
; // do nothing
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
}
Nguyên lý hệ điều hành
6.5
Nguyễn Đức Thịnh - ĐHNNHN
Consumer
while (true) {
while (count == 0)
; // do nothing
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
/* consume the item in nextConsumed */
}
Nguyên lý hệ điều hành
6.6
Nguyễn Đức Thịnh - ĐHNNHN
Race Condition

count++ có thể được cài đặt như sau
register1 = count
register1 = register1 + 1
count = register1

count– có thể được cài đặt như sau
register2 = count
register2 = register2 - 1
count = register2

Giả sử rằng ban đầu “count = 5”:
S0: producer thực thi register1 = count {register1 = 5}
S1: producer thực thi register1 = register1 + 1 {register1 = 6}
S2: consumer thực thi register2 = count {register2 = 5}
S3: consumer thực thi register2 = register2 - 1 {register2 = 4}
S4: producer thực thi count = register1 {count = 6 }
S5: consumer thực thi count = register2 {count = 4}
Nguyên lý hệ điều hành
6.7
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp cho Vấn đề Critical Section
1. Mutual Exclusion – Nếu process Pi đang thực thi trong critical section
của nó, thì không có process nào khác được thực thi trong critical
section (của process đó).
2. Tiến độ (progress) – Nếu không có process nào đang thực thi trong
critical section và có một số process yêu cầu được vào critical section
của nó, thì sự lựa chọn process sẽ vào critical section không được
phép trì hoãn mãi.
3. Thời gian chờ đợi bị chặn (Bounded Waiting) – Số lần mà các process
khác được vào critical section sau khi một process yêu cầu được vào
critical section và trước khi yêu cầu đó được chấp thuận phải bị chặn.


Nguyên lý hệ điều hành
Giả sử rằng các process đều đang trong trạng thái thực thi
Không có giả sử nào liên quan tới tốc độ tương đối của N
process đó
6.8
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp Peterson
 Cho hai process
 Giả sử rằng các chỉ thị LOAD và STORE là nguyên tố; không thể bị
ngắt.
 Hai processes chia sẻ 2 biến:

int turn;
 boolean flag[2];
 Biến turn chỉ định process nào được vào critical section.
 Mảng flag được dùng để thông báo khi nào một process sẵn sàng
vào critical section. flag[i] = true khi process Pi sẵn sàng.
Nguyên lý hệ điều hành
6.9
Nguyễn Đức Thịnh - ĐHNNHN
Thuật toán cho process Pi
do {
flag[i] = TRUE;
turn = j;
while (flag[j] && turn == j);
critical section
flag[i] = FALSE;
remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.10
Nguyễn Đức Thịnh - ĐHNNHN
Phần cứng đồng bộ hóa
 Nhiều hệ thống cung cấp phần cứng hỗ trợ critical section
 Đơn bộ xử lý – có thể vô hiệu hóa ngắt
Code đang chạy không thể bị tạm ngừng
 Không hiệu quả trên các hệ đa xử lý
 OS sử dụng cách này khó mở rộng

 Các máy tính hiện đại cung cấp chỉ thị phần cứng nguyên tố
Nguyên tố = không thể ngắt được
 Có thể là kiểm tra một từ nhớ hoặc thiết lập giá trị
 Hoặc hoán đổi nội dung của hai từ nhớ

Nguyên lý hệ điều hành
6.11
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp cho Critical-section
Problem sử dụng Locks
do {
acquire lock
critical section
release lock
remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.12
Nguyễn Đức Thịnh - ĐHNNHN
Chỉ thị TestAndSet
 Định nghĩa:
boolean TestAndSet (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv:
}
Nguyên lý hệ điều hành
6.13
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp sử dụng TestAndSet
 Biến boolean chia sẻ được dùng làm khóa, khởi tạo bằng
false.
 Giải pháp:
do {
while ( TestAndSet (&lock ))
; // do nothing
//
critical section
lock = FALSE;
//
remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.14
Nguyễn Đức Thịnh - ĐHNNHN
Chỉ thị Swap
 Định nghĩa:
void Swap (boolean *a, boolean *b)
{
boolean temp = *a;
*a = *b;
*b = temp:
}
Nguyên lý hệ điều hành
6.15
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp sử dụng Swap
 Biến khóa boolean chia sẻ được khởi tạo bằng FALSE; mỗi process
có một biến chìa khóa địa phương
 Giải pháp:
do {
key = TRUE;
while ( key == TRUE)
Swap (&lock, &key );
//
critical section
lock = FALSE;
//
remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.16
Nguyễn Đức Thịnh - ĐHNNHN
Mutual Exclusion với TestandSet()
do {
waiting[i] = TRUE;
key = TRUE;
while (waiting[i] && key)
key = TestAndSet(&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);
Nguyên lý hệ điều hành
6.17
Nguyễn Đức Thịnh - ĐHNNHN
Semaphore

Công cụ đồng bộ hóa không yêu cầu busy waiting

Semaphore S – biến nguyên

Hai thao tác cơ bản để thay đổi S: wait() và signal()

Chỉ có thể truy cập thông qua hai thao tác nguyên tố:

wait (S) {
while S <= 0
; // no-op
S--;
}
 signal (S) {
S++;
}
Nguyên lý hệ điều hành
6.18
Nguyễn Đức Thịnh - ĐHNNHN
Semaphore được dùng
như công cụ đồng bộ hóa tổng quát
 Semaphore đếm – giá trị nguyên không bị giới hạn
 Semaphore nhị phân – nhận hai giá trị 0 và 1 còn được gọi là mutex lock
 Có thể cài đặt một semaphore đếm như một semaphore nhị phân
 Cung cấp mutual exclusion
Semaphore mutex;
// initialized to 1
do {
wait (mutex);
// Critical Section
signal (mutex);
// remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.19
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Semaphore
 Phải đảm bảo rằng không có hai process nào có thể thực thi wait() và
signal() trên cùng một semaphore tại cùng thời điểm
 Như vậy, cài đặt trở thành critical section problem khi wait và signal
được đặt trong critical section.

Có thể xảy ra busy waiting trong cài đặt critical section

Nhưng cài đặt ngắn gọn

Thời gian busy waiting trong critical section ít xảy ra
 Chú ý rằng ứng dụng có thể dùng nhiều thời gian trong critical section
và do đó đây không phải là cài đặt tốt.
Nguyên lý hệ điều hành
6.20
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Semaphore
không có Busy waiting
 Với mỗi semaphore có một waiting queue gắn với nó. Mỗi entry
trong một waiting queue có hai data item:

giá trị (kiểu nguyên)

con trỏ tới phần tử kế tiếp trong danh sách
 Hai thao tác:

block – đặt tiến trình gọi nó vào waiting queue thích hợp.

wakeup – gỡ bỏ một tiến trình trong waiting queue và đặt nó vào
ready queue.
Nguyên lý hệ điều hành
6.21
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Semaphore không có Busy waiting


Cài đặt của wait:
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
Cài đặt của signal:
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
Nguyên lý hệ điều hành
6.22
Nguyễn Đức Thịnh - ĐHNNHN
Deadlock và Starvation

Deadlock – hai process chờ vô hạn một event chỉ có thể được gây ra bởi một
trong số các process đó.

Giả sử S và Q là hai semaphore được khởi tạo bằng 1
P0
P1
wait (S);
wait (Q);
wait (Q);
wait (S);
.
.
.
.
.
.
signal (S);
signal (Q);
signal (Q);
signal (S);

Starvation –block vô thời hạn. Một process có thể không bao giờ được gỡ bỏ
khỏi semaphore queue mà nó đang bị tạm ngừng trong đó

Priority Inversion – vấn đề lập lịch khi process có độ ưu tiên thấp giữ khóa
cần thiết cho process có độ ưu tiên cao hơn.
Nguyên lý hệ điều hành
6.23
Nguyễn Đức Thịnh - ĐHNNHN
Các vấn đề cổ điển trong đồng bộ hóa
 Vấn đề Bounded-Buffer
 Vấn đề Reader và Writer
 Vấn đề Dining-Philosopher
Nguyên lý hệ điều hành
6.24
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Bounded-Buffer
 N buffer, mỗi buffer lưu một item
 Semaphore mutex được khởi tạo bằng 1
 Semaphore full được khởi tạo bằng 0
 Semaphore empty được khởi tạo bằng N.
Nguyên lý hệ điều hành
6.25
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Bounded Buffer

Producer process
do {
// produce an item in nextp
wait (empty);
wait (mutex);
// add the item to the buffer
signal (mutex);
signal (full);
} while (TRUE);
Nguyên lý hệ điều hành
6.26
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Bounded Buffer

Consumer process
do {
wait (full);
wait (mutex);
// remove an item from buffer to nextc
signal (mutex);
signal (empty);
// consume the item in nextc
} while (TRUE);
Nguyên lý hệ điều hành
6.27
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Reader-Writer
 Một tập dữ liệu được chia sẻ bởi các process chạy song song.

Reader – chỉ đọc dữ liệu

Writers – có thể đọc và ghi
 Vấn đề – cho phép nhiều reader đọc đồng thời. Chỉ có một writer có
thể truy cập dữ liệu chia sẻ tại mỗi thời điểm.
 Dữ liệu chia sẻ

Tập dữ liệu

Semaphore mutex khởi tạo bằng 1

Semaphore wrt khởi tạo bằng 1

Số nguyên readcount khởi tạo bằng 0
Nguyên lý hệ điều hành
6.28
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Reader-Writer
 Writer process
do {
wait (wrt) ;
//
writing is performed
signal (wrt) ;
} while (TRUE);
Nguyên lý hệ điều hành
6.29
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Reader-Writer

Reader process
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);
Nguyên lý hệ điều hành
6.30
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Dining-Philosopher
 Dữ liệu chia sẻ

Bát cơm (data set)

Semaphore chopstick [5] khởi tạo bằng 1
Nguyên lý hệ điều hành
6.31
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề Dining-Philosophers

Philosopher i:
do {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );
// critical section
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
// remainder section
} while (TRUE);
Nguyên lý hệ điều hành
6.32
Nguyễn Đức Thịnh - ĐHNNHN
Vấn đề về Semaphores
 Cách dùng không đúng các semaphore operation:

signal (mutex) …. wait (mutex)

wait (mutex) … wait (mutex)

Bỏ qua wait (mutex) hoặc signal (mutex) hoặc cả hai
Nguyên lý hệ điều hành
6.33
Nguyễn Đức Thịnh - ĐHNNHN
Monitor

Một công cụ hiệu quả và tiện lợi để đồng bộ hóa tiến trình

Chỉ một process có thể chạy trong monitor tại mỗi thời điểm
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }
…
procedure Pn (…) {……}
Initialization code ( ….) { … }
…
}
}
Nguyên lý hệ điều hành
6.34
Nguyễn Đức Thịnh - ĐHNNHN
Sơ đồ của Monitor
Nguyên lý hệ điều hành
6.35
Nguyễn Đức Thịnh - ĐHNNHN
Biến điều kiện
 Điều kiện x, y;
 Hai thao tác trên biến điều kiện:

x.wait () – tạm ngừng process gọi hàm này.

x.signal () – khôi phục một process (nếu có) đã
gọi x.wait ()
Nguyên lý hệ điều hành
6.36
Nguyễn Đức Thịnh - ĐHNNHN
Monitor với các biến điều kiện
Nguyên lý hệ điều hành
6.37
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp cho Dining Philosophers
monitor DP
{
enum {THINKING; HUNGRY, EATING} state [5] ;
condition self [5];
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self [i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
Nguyên lý hệ điều hành
6.38
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp cho Dining Philosophers
void test (int i) {
if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Nguyên lý hệ điều hành
6.39
Nguyễn Đức Thịnh - ĐHNNHN
Giải pháp cho Dining Philosophers
 Mỗi philosopher i gọi các hàm pickup() và putdown() theo thứ tự sau:
DiningPhilosophters.pickup (i);
EAT
DiningPhilosophers.putdown (i);
Nguyên lý hệ điều hành
6.40
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Monitor Sử dụng Semaphores

Biến
semaphore mutex; // (khởi tạo = 1)
semaphore next; // (khởi tạo = 0)
int next-count = 0;

Mỗi thủ tục F được thay thế bởi:
wait(mutex);
…
body of F;
…
if (next_count > 0)
signal(next)
else
signal(mutex);

Mutual exclusion trong một monitor được đảm bảo.
Nguyên lý hệ điều hành
6.41
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Monitor

Với mỗi biến điều kiện x, ta có:
semaphore x_sem; // (khởi tạo = 0)
int x-count = 0;

Thao tác x.wait có thể được cài đặt như sau:
x-count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x_sem);
x-count--;
Nguyên lý hệ điều hành
6.42
Nguyễn Đức Thịnh - ĐHNNHN
Cài đặt Monitor
 Thao tác x.signal can be implemented as:
if (x-count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
Nguyên lý hệ điều hành
6.43
Nguyễn Đức Thịnh - ĐHNNHN
Monitor dùng cho cấp phát tài nguyên
monitor ResourceAllocator
{
boolean busy;
condition x;
void acquire(int time) {
if (busy)
x.wait(time);
busy = TRUE;
}
void release() {
busy = FALSE;
x.signal();
}
initialization code() {
busy = FALSE;
}
}
Nguyên lý hệ điều hành
6.44
Nguyễn Đức Thịnh - ĐHNNHN
Ví dụ đồng bộ hóa
 Solaris
 Windows XP
 Linux
 Pthreads
Nguyên lý hệ điều hành
6.45
Nguyễn Đức Thịnh - ĐHNNHN
Đồng bộ hóa trong Solaris
 Cài đặt một số khóa hỗ trợ đa nhiệm, đa luồng (bao gồm các luồng
thời gian thực), và đa bộ xử lý
 Sử dụng các adaptive mutex để tăng tính hiệu quả khi bảo vệ dữ liệu
khỏi các code segment ngắn
 Sử dụng các biến điều kiện và reader-writer lock khi các code
segment dài hơn yêu cầu truy cập dữ liệu
 Sử dụng turnstiles để sắp xếp danh sách các luồng đang chờ để
nhận được hoặc một adaptive mutex hoặc reader-writer lock
Nguyên lý hệ điều hành
6.46
Nguyễn Đức Thịnh - ĐHNNHN
Đồng bộ hóa trong Windows XP
 Sử dụng mặt nạ ngắt (interrupt masks) để ngăn cản các truy cập tới
tài nguyên hệ thống trong các hệ đơn bộ xử lý
 Sử dụng spinlocks trong các hệ đa bộ xử lý
 Cung cấp các dispatcher object hoạt động như mutex và
semaphore
 Dispatcher object có thể còn cung cấp event

Một event hoạt động tương tư như một biến điều kiện
Nguyên lý hệ điều hành
6.47
Nguyễn Đức Thịnh - ĐHNNHN
Linux Synchronization
 Linux:

Trước khi có nhân version 2.6, vô hiệu hóa interrupt để cài đặt các
critical section ngắn

Từ version 2.6 về sau, hoàn toàn preemptive
 Linux cung cấp:

semaphore

spin lock
Nguyên lý hệ điều hành
6.48
Nguyễn Đức Thịnh - ĐHNNHN
Pthreads Synchronization
 Pthreads API độc lập với OS
 Các chức năng:

mutex lock

condition variable
 Các mở rộng non-portable còn bao gồm:

read-write lock

spin lock
Nguyên lý hệ điều hành
6.49
Nguyễn Đức Thịnh - ĐHNNHN
Hết chương 6
Nguyên lý hệ điều hành
Nguyễn Đức Thịnh - ĐHNNHN