1
1
Nguyên lý hệđiềuhành
NguyễnHải Châu
Khoa Công nghệ thông tin
Trường Đạihọc Công nghệ
2
Đồng bộ hóa tiếntrình
3
Ví dụđồng bộ hóa (1)
TiếntrìnhghiP:
while (true) {
while (counter==SIZE) ;
buf[in] = nextItem;
in = (in+1) % SIZE;
counter++;
}
buf: Buffer
SIZE: cỡ của buffer
counter: Biến chung
Tiếntrìnhđọc Q:
while (true) {
while (counter==0) ;
nextItem = buf[out];
out = (out+1) % SIZE;
counter ;
}
z Đây là bài toán vùng
đệmcógiớihạn
4
Ví dụđồng bộ hóa (2)
z counter++
register
1
= counter;
register
1
= register
1
+ 1;
counter = register
1
;
z counter
register
2
= counter;
register
2
= register
2
-1;
counter = register
2
;
z Các toán tử ++ và có thểđượccàiđặtnhư sau:
P và Q có thể nhận được các giá trị khác nhau của
counter tại cùng 1 thời điểmnếunhưđoạnmãxanh
và đỏ thựchiệnxenkẽ nhau.
5
Ví dụđồng bộ hóa (3)
z Giả sử P và Q thựchiện song song vớinhau
và giá trị của counter là 5:
register
1
= counter; // register
1
=5
register
1
= register
1
+ 1; // register
1
=6
register
2
= counter; // register
2
=5
register
2
= register
2
-1; // register
2
=4
counter = register
1
; // counter=6 !!
counter = register
2
; // counter=4 !!
6
Ví dụđồng bộ hóa (4)
z Lỗi: Cho phép P và Q đồng thờithao táctrên
biếnchungcounter. Sửalỗi:
register
1
= counter; // register
1
=5
register
1
= register
1
+ 1; // register
1
=6
counter = register
1
; // counter=6
register
2
= counter; // register
2
=6
register
2
= register
2
-1; // register
2
=5
counter = register
2
; // counter=5
2
7
Tương tranh và đồng bộ
z Tình huống xuấthiệnkhinhiềutiếntrìnhcùng
thao tác trên dữ liệu chung và kếtquả các
thao tác đóphụ thuộcvàothứ tự thựchiện
củacáctiếntrìnhtrêndữ liệu chung gọilàtình
huống tương tranh (race condition)
z Để tránh các tình huống tương tranh, các tiến
trình cần được đồng bộ theo mộtphương
thứcnàođó ⇒ Vấn đề nghiên cứu: Đồng bộ
hóa các tiếntrình
8
Khái niệmvềđoạnmãgăng (1)
z Thuậtngữ: Critical section
z Thuậtngữ tiếng Việt: Đoạnmãgăng, đoạn
mã tớihạn.
z Xét mộthệ có n tiếntrìnhP
0
, P
1
, , P
n
, mỗi
tiến trình có một đoạnmãlệnh gọilàđoạn
mã găng, ký hiệulàCS
i
, nếunhư trong đoạn
mã này, các tiến trình thao tác trên các biến
chung, đọc ghi file (tổng quát: thao tác trên
dữ liệu chung)
9
Khái niệmvềđoạnmãgăng (2)
z Đặc điểm quan trọng mà hệ n tiến trình này
cầncólà: KhimộttiếntrìnhP
i
thựchiện đoạn
mã CS
i
thì không có tiếntrìnhP
j
nào khác
đượcphépthựchiện CS
j
z MỗitiếntrìnhP
i
phải “xin phép” (entry
section) trướckhithựchiện CS
i
và thông báo
(exit section) cho các tiến trình khác sau khi
thựchiện xong CS
i
.
10
Khái niệmvềđoạnmãgăng (3)
z Cấu trúc chung của P
i
để thựchiện đoạnmã
găng CS
i
.
do {
Xin phép (ENTRY
i
) thựchiện CS
i
; // Entry section
Thựchiện CS
i
;
Thông báo (EXIT
i
) đãthựchiệnxongCS
i
; // Exit section
Phầnmãlệnh khác (REMAIN
i
); // Remainder section
} while (TRUE);
11
Khái niệmvềđoạnmãgăng (4)
z Viếtlạicấutrúcchungcủa đoạnmãgăng:
do {
ENTRY
i
; // Entry section
Thựchiện CS
i
; // Critical section
EXIT
i
; // Exit section
REMAIN
i
; // Remainder section
} while (TRUE);
12
Giải pháp cho đoạnmãgăng
z Giải pháp cho đoạnmãgăng cầnthỏa mãn 3
điềukiện:
z Loạitrừ lẫn nhau (mutual exclusion): Nếu P
i
đang
thựchiện CS
i
thì P
j
không thể thựchiện CS
j
∀j≠i.
z Tiếntriển (progress): Nếu không có tiếntrìnhP
i
nào
thựchiện CS
i
và có m tiếntrìnhP
j1
, P
j2
, , P
jm
muốn
thựchiện CS
j1
, CS
j2
, , CS
jm
thì chỉ có các tiếntrình
không thựchiện REMAIN
jk
(k=1, ,m) mới đượcxem
xét thựchiện CS
jk
.
z Chờ có giớihạn (bounded waiting): sau khi mộttiến
trình P
i
có yêu cầuvàoCS
i
và trướckhiyêu cầu đó
đượcchấpnhận, số lầncáctiếntrìnhP
j
(với j≠i) được
phép thựchiện CS
j
phảibị giớihạn.
3
13
Ví dụ: giảiphápcủa Peterson
z Giả sử có 2 tiếntrìnhP
0
và P
1
với hai đoạn
mã găng tương ứng CS
0
và CS
1
z Sử dụng mộtbiến nguyên turn vớigiátrị khởi
tạo0 hoặc1 vàmảng boolean flag[2]
z turn có giá trị i có nghĩalàP
i
đượcphépthực
hiện CS
i
(i=0,1)
z nếu flag[i] là TRUE thì tiếntrìnhP
i
đãsẵn
sàng để thựchiện CS
i
14
Ví dụ: giảiphápcủa Peterson
z Mã lệnh của P
i
:
do {
flag[i] = TRUE;
turn = j;
while (flag[j] && turn == j) ;
CS
i
;
flag[j] = FALSE;
REMAIN
i
;
} while (1);
15
Chứng minh giải pháp Peterson
z Xem chứng minh giảiphápcủa Peterson
thỏa mãn 3 điềukiệncủa đoạnmãgăng
trong giáo trình (trang 196)
z Giải pháp “kiểu Peterson”:
z Phứctạpkhisố lượng tiếntrìnhtăng lên
z Khó kiểm soát
16
Semaphore
17
Thông tin tham khảo
z Edsger Wybe Dijkstra
(người Hà Lan) phát
minh ra khái niệm
semaphore trong khoa
học máy tính vào năm
1972
z Semaphore được sử
dụng lần đầutiêntrong
cuốnsách“The
operating system” của
ông
Edsger Wybe Dijkstra
(1930-2002)
18
Định nghĩa
z Semaphore là mộtbiến nguyên, nếu không tính
đếntoántử khởitạo, chỉ có thể truy cập thông
qua hai toán tử nguyên tố là wait (hoặcP) và
signal (hoặcV).
z P: proberen – kiểmtra(tiếng Hà Lan)
z V: verhogen–tăng lên (tiếng Hà Lan)
z Các tiếntrìnhcóthể sử dụng chung semaphore
z Các toán tử là nguyên tốđểđảmbảo không xảy
ra trường hợpnhư ví dụđồng bộ hóa đãnêu
4
19
Toán tử wait và signal
wait(S) // hoặcP(S)
{
while (S<=0);
S ;
}
z Toán tử wait: Chờ khi
semaphore S âm và
giảmS đi1 nếuS>0
signal(S) // hoặcV(S)
{
S++;
}
z Toán tử signal: Tăng S
lên 1
20
Sử dụng semaphore (1)
z Với bài toán đoạnmãgăng:
do {
wait(mutex); // mutex là semaphore khởitạo1
CS
i
;
signal(mutex);
REMAIN
i
;
} while (1);
21
Sử dụng semaphore (2)
z P
1
:
O
1
;
signal(synch);
z P
2
:
wait(synch);
O
2
;
z Xét hai tiếntrìnhP
1
và P
2
, P
1
cầnthựchiện
toán tử O
1
, P
2
cầnthựchiện O
2
và O
2
chỉ
đượcthựchiện sau khi O
1
đãhoànthành
z Giải pháp: Sử dụng semaphore synch = 0
22
Cài đặt semaphore cổđiển
z Định nghĩacổđiểncủawait chotathấytoán
tử này có chờ bận (busy waiting), tứclàtiến
trình phảichờ toán tử wait kết thúc nhưng
CPU vẫnphảilàmviệc: Lãng phí tài nguyên
z Liên hệ cơ chế polling trong kiến trúc máy tính
z Cài đặt semaphore theo định nghĩacổđiển:
z Lãng phí tài nguyên CPU với các máy tính 1 CPU
z Có lợinếuthờigianchờ wait ít hơnthờigianthực
hiện context switch
z Các semaphore loạinàygọilàspinlock
23
Cài đặt semaphore theo cấutrúc
z Khắcphụcchờ bận: Chuyểnvònglặpchờ
thành việcsử dụng toán tử block (tạmdừng)
z Để khôi phụcthựchiệntừ block, ta có toán tử
wakeup
z Khi đó để cài đặt, ta có cấutrúcdữ liệumới
cho semaphore:
typedef struct {
int value; // Giá trị của semaphore
struct process *L; // Danh sách tiếntrìnhchờ
} semaphore;
24
void wait(semaphore *S)
{
S->value ;
if (S->value<0) {
Thêm tiếntrìnhgọi
toán tử vào s->L;
block();
}
}
void signal(semaphore *S)
{
S->value++;
if (S->value<=0) {
Xóa mộttiếntrìnhP
ra khỏis->L;
wakeup(P);
}
}
Cài đặt semaphore theo cấutrúc
5
25
Semaphore nhị phân
z Là semaphore chỉ nhậngiátrị 0 hoặc1
z Cài đặt semaphore nhị phân đơngiảnhơn
semaphore không nhị phân (thuậtngữ:
counting semaphore)
26
Mộtsố bài toán
đồng bộ hóa cơ bản
27
Bài toán vùng đệmcógiớihạn
z Đãxétở ví dụđầu tiên (the bounded-buffer
problem)
z Ta sử dụng 3 semaphore tên là full, empty và
mutex để giải quyết bài toán này
z Khởitạo:
z full: Số lượng phầntử buffer đãcódữ liệu(0)
z empty: Số lượng phầntử buffer chưacódữ liệu(n)
z mutex: 1 (Chưacótiến trình nào thựchiện đoạn
mã găng)
28
Bài toán vùng đệmcógiớihạn
TiếntrìnhghiP:
do {
wait(empty);
wait(mutex);
// Ghi mộtphầntử mới
// vào buffer
signal(mutex);
signal(full);
} while (TRUE);
Tiếntrìnhđọc Q:
do {
wait(full);
wait(mutex);
// Đọcmộtphầntử ra
// khỏi buffer
signal(mutex);
signal(empty);
} while (TRUE);
29
Bài toán tiếntrìnhđọc - ghi
z Thuậtngữ: the reader-writer problem
z Tình huống: Nhiềutiến trình cùng thao tác trên mộtcơ
sở dữ liệutrongđó
z Mộtvàitiếntrìnhchỉđọcdữ liệu(kýhiệu: reader)
z Mộtsố tiếntrìnhvừa đọcvừa ghi (ký hiệu: writer)
z Khi có đọc/ghi đồng thờicủanhiềutiến trình trên cùng
mộtcơ sở dữ liệu, có 2 bài toán:
z Bài toán 1: reader không phảichờ,trừ khi writer đã đượcphép
ghi vào CSDL (hay các reader không loạitrừ lẫn nhau khi đọc)
z Bài toán 2: Khi writer đãsẵn sàng ghi, nó sẽ được ghi trong
thời gian sớm nhất (nói cách khác khi writer đã sẵn sàng,
không cho phép các reader đọcdữ liệu)
30
Bài toán tiếntrìnhđọc-ghi số 1
z Sử dụng các semaphore vớigiátrị khởitạo:
wrt (1), mutex (1)
z Sử dụng biến rcount (khởitạo0) để đếmsố
lượng reader đang đọcdữ liệu
z wrt: Đảmbảoloạitrừ lẫn nhau khi writer ghi
z mutex: Đảmbảoloạitrữ lẫnnhaukhicập
nhậtbiến rcount
6
31
Bài toán tiếntrìnhđọc-ghi số 1
z Tiếntrìnhwriter P
w
:
do {
wait(wrt);
// Thao tác ghi đang được
// thựchiện
signal(wrt);
while (TRUE);
z Tiến trình reader P
r
:
do {
wait(mutex);
rcount++;
if (rcount==1) wait(wrt);
signal(mutex);
// Thựchiện phép đọc
wait(mutex);
rcount ;
if (rcount==0) signal(wrt);
signal(mutex);
} while (TRUE);
32
Bữa ăntốicủacáctriếtgia
z Thuậtngữ: the dining-
philosophers problem
z Có 5 triếtgia, 5 chiếc
đũa, 5 bát cơmvàmột
âu cơmbố trí như hình
vẽ
z Đây là bài toán cổđiển
và là ví dụ minh họa
cho mộtlớpnhiềubài
toán tương tranh
(concurrency): Nhiều
tiến trình khai thác
nhiều tài nguyên chung
33
Bữa ăntốicủacáctriếtgia
z Các triếtgiachỉ làm 2 việc: Ănvàsuynghĩ
z Suy nghĩ: Không ảnh hưởng đếncáctriếtgiakhác,
đũa, bátvàâucơm
z Để ăn: Mỗitriếtgiaphảicóđủ 2 chiếc đũagầnnhất ở
bên phải và bên trái mình; chỉđượclấy 1 chiếc đũa
mộtlầnvàkhôngđượcphéplấy đũatừ tay triếtgia
khác
z Khi ăn xong: Triếtgiabỏ cả hai chiếc đũaxuống bàn
và tiếptụcsuynghĩ
34
Giải pháp cho bài toán Bữa ăn
z Biểudiễn5 chiếc đũa qua
mảng semaphore:
semaphore chopstick[5];
các semaphore đượckhởitạo
giá trị 1
z Mã lệnh củatriếtgianhư hình
bên
z Mã lệnh này có thể gây bế tắc
(deadlock) nếucả 5 triếtgia
đềulấy được1 chiếc đũavà
chờđểlấychiếccònlạinhưng
không bao giờ lấy được!!
z Mã lệnh củatriếtgiai:
do {
wait(chopstick[i]);
wait(chopstick[(i+1)%5];
// Ăn
signal(chopstick[i]);
signal(chopstick[(i+1)%5];
// Suy nghĩ
} while (TRUE);
35
Mộtsố giảipháptránhbế tắc
z Chỉ cho phép nhiềunhất 4 triếtgiađồng thời
lấy đũa, dẫn đếncóítnhất1 triếtgialấy
được 2 chiếc đũa
z Chỉ cho phép lấy đũakhicả hai chiếc đũa
bên phải và bên trái đềunằmtrênbàn
z Sử dụng giảiphápbất đốixứng: Triếtgia
mang số lẻ lấychiếc đũa đầutiênở bên trái,
sau đóchiếc đũa ở bên phải; triếtgiamang
số chẵnlấychiếc đũa đầutiênở bên phải,
sau đólấychiếc đũabêntrái
36
Hạnchế của semaphore
z Mặc dù semaphore cho ta cơ chếđồng bộ
hóa tiệnlợi song sử dụng semaphore không
đúngcáchcóthể dẫn đếnbế tắchoặclỗido
trình tự thựchiệncủacáctiếntrình
z Trong mộtsố trường hợp: khó phát hiệnbế
tắchoặclỗi do trình tự thựchiệnkhisử dụng
semaphore không đúng cách
z Sử dụng không đúng cách gây ra bởi lỗilập
trình hoặc do ngườilập trình không cộng tác
7
37
Ví dụ hạnchế của semaphore (1)
z Xétvídụ vềđoạnmãgăng:
z Mã đúng:
wait(mutex);
// Đoạnmãgăng
signal(mutex);
z Mã sai:
signal(mutex);
// Đoạnmãgăng
wait(mutex);
z Đoạn mã sai này gây ra
vi phạm điềukiệnloại
trữ lẫn nhau
38
Ví dụ hạnchế của semaphore (2)
z Xétvídụ vềđoạnmãgăng:
z Mã đúng:
wait(mutex);
// Đoạnmãgăng
signal(mutex);
z Mã sai:
wait(mutex);
// Đoạnmãgăng
wait(mutex);
z Đoạn mã sai này gây ra
bế tắc
39
Ví dụ hạnchế của semaphore (3)
z Nếungườilập trình quên các toán tử wait()
hoặc signal() trong trong các đoạnmãgăng,
hoặccả hai thì có thể gây ra:
z Bế tắc
z Vi phạm điềukiệnloạitrừ lẫnnhau
40
z Tiến trình P
1
wait(S);
wait(Q);
signal(S);
signal(Q);
z Tiến trình P
2
wait(Q);
wait(S);
signal(Q);
signal(S);
Ví dụ hạnchế của semaphore (4)
z Hai tiến trình P
1
và P
2
đồng thời thực hiện sẽ
dẫn tới bế tắc
41
Cơ chế monitor
42
Thông tin tham khảo
z Per Brinch Hansen
(người Đan Mạch) là
người đầutiênđưara
khái niệmvàcàiđặt
monitor năm1972
z Monitor được sử dụng
lần đầu tiên trong ngôn
ngữ lập trình Concurrent
Pascal
Per Brinch Hansen
(1938-2007)
8
43
Monitor là gì?
z Thuật ngữ monitor: giám sát
z Định nghĩa không hình thức: Là mộtloại
construct trong ngôn ngữ bậc cao dùng để
phụcvụ các thao tác đồng bộ hóa
z Monitor đượcnghiêncứu, phát triển để khắc
phụccáchạnchế của semaphore nhưđã
nêu trên
44
Định nghĩa tổng quát
z Monitor là một cách tiếp cận để đồng bộ hóa
các tác vụ trên máy tính khi phải sử dụng các
tài nguyên chung. Monitor thường gồm có:
z Tập các procedure thao tác trên tài nguyên chung
z Khóa loại trừ lẫn nhau
z Các biến tương ứng với các tài nguyên chung
z Một số các giả định bất biến nhằm tránh các tình
huống tương tranh
z Trong bài này: Nghiên cứu một loại cấu trúc
monitor: Kiểu monitor (monitor type)
45
Monitor type
z Mộtkiểu(type) hoặckiểutrừutượng (abstract
type) gồmcócácdữ liệu private và các phương
thức public
z Monitor type được đặc trưng bởi tập các toán
tử củangườisử dụng định nghĩa
z Monitor type có các biếnxácđịnh các trạng
thái; mã lệnh của các procedure thao tác trên
các biến này
46
Cấutrúcmột monitor type
monitor tên_monitor {
// Khai báo các biến chung
procedure P1( ) {
}
procedure P2( ) {
}
procedure Pn( ) {
}
initialization_code ( ) {
}
}
47
Minh họacấu trúc monitor
48
Cách sử dụng monitor
z Monitor đượccài đặt sao cho chỉ có mộttiến
trình đượchoạt động trong monitor (loại trừ
lẫn nhau). Ngườilậptrìnhkhôngcầnviếtmã
lệnh để đảm bảo điều này
z Monitor nhưđịnh nghĩatrênchưa đủ mạnh
để xử lý mọitrường hợp đồng bộ hóa. Cần
thêm mộtsố cơ chế “tailor-made” vềđồng bộ
hóa
z Các trường hợp đồng bộ hóa “tailor-made”:
sử dụng kiểu condition.
9
49
Kiểu condition
z Khai báo:
condition x, y; // x, y là các biếnkiểu condition
z Sử dụng kiểu condition: Chỉ có 2 toán tử là
wait và signal
z x.wait(): tiếntrìnhgọi đến x.wait() sẽđược chuyển
sang trạng thái chờ (wait hoặc suspend)
z x.signal(): tiếntrìnhgọi đến x.signal() sẽ khôi
phục việc thực hiện (wakeup) mộttiếntrìnhđãgọi
đến x.wait()
50
Monitor có kiểu condition
51
Đặc điểmcủa x.signal()
z x.signal() chỉđánh thức duy nhấtmộttiến
trình đang chờ
z Nếukhôngcótiếntrìnhchờ, x.signal() không
có tác dụng gì
z x.signal() khác với signal trong semaphore cổ
điển: signal cổđiển luôn làm thay đổitrạng
thái (giá trị) của semaphore
52
Signal wait/continue
z Giả sử có hai tiếntrìnhP vàQ:
z Q gọi đến x.wait(), sau đó P gọi đếnx.signal()
z Q đượcphéptiếptụcthựchiện (wakeup)
z Khi đó P phảivàotrạng thái wait vì nếungược
lạithìP và Q cùng thựchiện trong monitor
z Khả năng xảyra:
z Signal-and-wait: P chờđếnkhiQ rờimonitor hoặc
chờ một điềukiện khác (*)
z Signal-and-continue: Q chờđếnkhiP rời monitor
hoặcchờ một điềukiệnkhác
53
Bài toán Ăntối với monitor
z Giải quyết bài toán Ăntốicủacáctriếtgiavới
monitor để không xảyrabế tắckhihai triếtgiangồi
cạnh nhau cùng lấy đũa để ăn
z Trạng thái củacáctriếtgia:
enum {thinking, hungry, eating} state[5];
z Triếtgiai chỉ có thểănnếucả hai ngườingồicạnh
ông ta không ăn:
(state[(i+4)%5]!=eating) and (state[(i+1)%5]!=eating)
z Khi triếtgiai không đủ điềukiện để ăn: cầncóbiến
condition: condition self[5];
54
Monitor củabàitoánĂntối
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();
}
}
10
55
Monitor củabàitoánĂntối
void putdown(int i) {
state[i] = thinking;
test((i+4)%5);
test((i+1)%5);
}
initialization_code() {
for (int i=0;i<5;i++) state[i] = thinking;
}
56
Monitor củabàitoánĂntối
void test(int i) {
if ((state[(i+4)%5] != eating) &&
(state[i] == hungry) &&
(state[(i+1)%5] != eating)) {
state[i] = eating;
self[i].signal();
}
}
57
Đọcthêmở nhà
z Khái niệmvề miềngăng (critical region)
z Cơ chế monitor của Java:
public class XYZ {
public synchronized void safeMethod() {
}
}
z Toán tử wait() và notify() trong java.util.package
(tương tự toán tử wait() và signal())
z Cách cài đặt monitor bằng semaphore
58
Tóm tắt
z Khái niệm đồng bộ hóa
z Khái niệm đoạnmãgăng, ba điềukiệncủa
đoạnmãgăng
z Khái niệm semaphore, semaphore nhị phân
z Hiệntượng bế tắc do sử dụng sai semaphore
z Mộtsố bài toán cổđiểntrongđồng bộ hóa
z Miềngăng
z Cơ chế monitor
59
Bài tập
z Chỉ ra điềukiệnnàocủa đoạnmãgăng bị vi
phạm trong đoạnmãgăng sau của P
i
:
do {
while (turn != i) ;
CS
i
;
turn = j;
REMAIN
i
;
} while (1);
60
Bài tập
z Cài đặt giải pháp cho bài toán Bữa ăn tối của
các triết gia trong Java bằng cách sử dụng
synchronized, wait() và notify()
z Giải pháp monitor cho bài toán Bữa ăn tối
tránh được bế tắc, nhưng có thể xảy ra
trường hợp tất cả các triết gia đều không
được ăn. Hãy chỉ ra trường hợp này và tìm
cách giải quyết bằng cơ chế monitor
z Chú ý: Sinh viên cần làm bài tập để hiểu tốt
hơn về đồng bộ hóa