1 1 Nguyênlý 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 . 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. 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 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ó