II.2.1 Tài nguyên găng Critical Resource Trong môi trường hệ điều hành đa nhiệm - đa chương – đa người sử dụng, việc chia sẻ tài nguyên cho các tiến trình của người sử dụng dùng chung là[r]
(1)ĐẠI HỌC ĐÀ NẴNG TRƯỜNG ĐẠI HỌC BÁCH KHOA KHOA CÔNG NGHỆ THÔNG TIN ĐỒ ÁN MÔN HỌC NGUYÊN LÝ HỆ ĐIỀU HÀNH ĐỀ TÀI : BÀI TOÁN NĂM TRIẾT GIA Người hướng dẫn : NGUYỄN VĂN NGUYÊN Sinh viên thực : BÙI VŨ NHẬT HOÀNG Lớp : 06T3 Đà nẵng, 01/2010 (2) LỜI CẢM ƠN Những kiến thức nâng cao hệ điều hành, nắm bắt nguyên tắc hoạt động Nguyên lý hệ điều hành là học phần quan trọng và bắt buộc tất sinh viên chuyên ngành công nghệ thông tin Nguyên lý hệ điều hành cung cấp cho sinh viên động hệ điều hành trên máy tính Hệ điều hành xem là thành phần trung gian hay là cầu nối cho giao tiếp người sử dụng và máy tính Thông qua hệ điều hành người sử dụng dễ dàng làm việc và khai thác hiệu thiết bị phần cứng máy tính, quản lý phần mềm ứng dụng Người sử dụng cần thao tác các lệnh, các kiện và chờ các tiến trình hệ điều hành thực Với Hệ điều hành có tiềm thế, chúng ta phải có nghiên cứu, hiểu biết nó, để có thể nắm bắt tốt các khái niệm chuyên ngành Hệ điều hành Em xin cảm ơn hướng dẫn tận tình thầy th.S Nguyễn Văn Nguyên đã giúp em hoàn thành đề tài này Sinh viên thực Bùi Vũ Nhật Hoàng (3) LỜI MỞ ĐẦU Nếu không có phần mềm, máy tính là thiết bị điện tử thông thường Với hỗ trợ phần mềm, máy tính có thể lưu trữ, xử lý thông tin và người sử dụng có thể gọi lại thông tin này Phần mềm máy tính có thể chia thành nhiều loại: chương trình hệ thống, quản lý hoạt động chính máy tính Chương trình ứng dụng, giải các vấn đề liên quan đến việc sử dụng và khai thác máy tính người sử dụng Hệ điều hành thuộc nhóm các chương trình hệ thống và nó là chương trình hệ thống quan trọng máy tính và người sử dụng Hệ điều hành điều khiển tất các tài nguyên máy tính và cung cấp môi trường thuận lợi để các chương trình ứng dụng người sử dụng viết có thể chạy trên máy tính Một máy tính đại có thể bao gồm: nhiều processor, nhớ chính, clocks, đĩa, giao diện mạng, và các thiết bị vào/ra khác Tất nó tạo thành hệ thống phức tạp Để viết các chương trình để theo dõi tất các thành phần máy tính và sử dụng chúng cách hiệu quả, người lập trình phải biết processor thực chương trình nào, nhớ lưu trữ thông tin nào, các thiết bị đĩa làm việc (ghi/đọc) nào, lỗi nào có thể xảy đọc block đĩa, … đây là công việc khó khăn và quá khó người lập trình Nhưng may cho người lập trình ứng dụng và người sử dụng là công việc trên đã hệ điều hành hỗ trợ nên họ không cần quan tâm đến chúng ta cần tiềm hiểu hệ điều hành để có cái nhìn tổng quan gì liên quan đến việc thiết kế cài đặt chức hệ điều hành để hệ điều hành đạt mục tiêu: Giúp người sử dụng khai thác máy tính dễ dàng và chương trình người sử dụng có thể chạy trên máy tính "Bài toán bữa tối các triết gia" (Dining Philosophers), bài toán kinh điển tương tranh và chia sẻ tài nguyên Việc nghiên cứu bài toán cho chúng ta hiểu rõ khía cạnh này hệ điều hành (4) PHỤ LỤC CHƯƠNG I BÀI TOÁN .5 I.1 Đề tài I.2 Mô tả vấn đề .5 I.3 Yêu cầu bài toán CHƯƠNG II CƠ SỞ LÝ THUYẾT II.1 Tiến trình (proccess) .6 II.1.1 Khái niệm II.1.2 Định nghĩa tiến trình II.1.3 Các loại tiến trình II.1.4 Tuyến (Thred) .6 II.2 Tài nguyên găng và đoạn găng .7 II.2.1 Tài nguyên găng (Critical Resource) II.2.2 Đoạn găng (Critical Section) .8 II.2.3 Yêu cầu đoạn găng II.3 Giải pháp Semaphore II.4 Deadlock II.4.1 Giới thiệu vấn đề II.4.2 Điều kiện hình thành tắt nghẽn 10 II.4.3 Ngăn chặn tắc nghẽn (Deadlock Prevention) 10 CHƯƠNG III CÁCH GIẢI QUYẾT BÀI TOÁN .11 III.1 Quản lý vùng găng 11 III.2 Giải pháp xử lý deadlock 13 III.3 Chương trình 13 III.3.1 Class Philosopher .14 III.3.2 Class Chopstick .15 III.3.3 Class Diner 15 III.3.4 Class PhilCanvas .15 CHƯƠNG IV KẾT QUẢ CHƯƠNG TRÌNH .16 IV.1.1 Chương trình tạm dừng 16 IV.1.2 Chương trình reset 17 CHƯƠNG V KẾT LUẬN 18 V.1.1 Đạt 18 V.1.2 Chưa đạt 18 (5) CHƯƠNG I I.1 BÀI TOÁN Đề tài Viết chương trình giải bài toán “Năm triết gia ăn tối” Chương trình tạo năm quá trình mô hoạt động năm triết gia Sử dụng Semaphore để đồng hoạt động năm triết gia này I.2 Mô tả vấn đề Đây là bài toán cổ điển hệ điều hành Bài toán bữa tối các triết gia đưa nhà toán học E W Dijkstra Bài toán mô tả sau : Có năm triết gia cùng ngồi ăn tối quanh bàn tròn, trước mặt người có đĩa mì Ý, triết gia thì có nĩa Mỗi triết gia dành toàn thời gian để suy nghĩ ăn đói Mỗi triết gia có thể ăn có nĩa bên cạnh mình Đói : triết gia có thể chết đói ông ta không có cách nào để ăn Tắc nghẽn : các triết gia phải đợi lẫn nên không có ăn I.3 Yêu cầu bài toán Phải đặt thuật toán cho triết gia bị đói thì ông ta ăn và đảm bảo không có triết gia nào bị chết đói Bài toán đặt vấn đề “đồng các tiến trình”, giải vấn đề tắc nghẽn có thể xảy Thuật toán đưa là thuật toán Semaphore (6) CHƯƠNG II II.1 CƠ SỞ LÝ THUYẾT Tiến trình (proccess) II.1.1 Khái niệm Tiến trình là phận chương trình thực hiện, đơn vị thực tiến trình là processer Vì tiến trình là phận chương trình nên tương tự chương trình tiến trình sở hữu trỏ lệnh, trỏ stack, tập các ghi, không gian địa nhớ chính và tất các thông tin cần thiết khác để tiến trình có thể hoạt động II.1.2 Định nghĩa tiến trình Định nghĩa Saltzer: Tiến trình là chương trình processor logic thực Định nghĩa Horning & Rendell: Tiến trình là quá trình chuyển từ trạng thái này sang trạng thái khác tác động hàm hành động, xuất phát từ trạng thái ban đầu nào đó II.1.3 Các loại tiến trình Các tiến trình hệ thống có thể chia thành hai loại: tiến trình và tiến trình song song Tiến trình là các tiến trình mà điểm khởi tạo nó là điểm kết thúc tiến trình trước đó Tiến trình song song là các tiến trình mà điểm khởi tạo tiến trình này mằn thân các tiến trình khác, tức là có thể khởi tạo tiến trình các tiến trình trước đó chưa kết thúc Tiến trình xuất các hệ điều hành đơn nhiệm hệ điều hành MSDOS Các tiến trình song song xuất hệ điều hành đa nhiệm Các tiến trình song song II.1.4 Tuyến (Thred) Tuyến là thành phần tiến trình sở hữu ngăn xếp và thực thi độc lập mã lệnh tiến trình Nếu hệ điều hành có nhiều tiến trình thì tiến trình bạn có thể tạo nhiều tuyến hoạt dộng song song với tương tự các tiến trình hoạt động song song hệ điều hành Ưu điểm tuyến là chúng hoạt động cùng không gian địa tiến trình Tập hợp nhóm các tuyến có thể sử dụng chung biến toàn cục, vùng nhớ heap, bảng mô tả file… (7) tiến trình, chế liên lạc các tuyến đơn giản và hiệu chế liên lạc các tiến trình với ( hệ điều hành bạn chạy trên phần cứng nhiều xử lí thì tuyến thực chạy song song không phải giả lập kiểu xoay vòng ) Ưu điểm sử dụng tuyến tiến trình đơn giản lập trình Nhiều thao tác xuất nhập hiển thị liệu có thể tách rời và phân cho các tuyến chạy độc lập thực thi Ví dụ môi trường đồ họa, bạn copy file có kích thước lớn, chương trình thiết kế cho tuyến thực đọc ghi liệu từ đĩa, tuyến khác đảm trách việc hiển thị phần trăm hoàn thành công việc cho người dùng theo dõi tiến độ Đối với hệ điều hành chi phí để chuyển đổi ngữ cảnh tiến trình cao và chậm chi phí chuyển đổi ngữ cảnh dành cho tuyến ( với tiến trình hệ điều hành phải cất thông số môi trường, ghi trạng thái, hoán đổi vùng nhớ…) Tuy nhiên, điểm yếu việc dùng tuyến đó là khả đổ tuyến ảnh hưởng đến tất các tuyến khác và toàn tiến trình hoạt động Lí là các tuyến dùng chung vùng nhớ và không gian địa tiến trình Ngược lại, tiến trình bị đổ vỡ luôn hệ điều hành cô lập hoàn toàn không gây ảnh hưởng đến các tiến trình khác Tiến trình có thể chạy trên nhiều máy khác tuyến thực thi trên máy và tiến trình II.2 Tài nguyên găng và đoạn găng II.2.1 Tài nguyên găng (Critical Resource) Trong môi trường hệ điều hành đa nhiệm - đa chương – đa người sử dụng, việc chia sẻ tài nguyên cho các tiến trình người sử dụng dùng chung là cần thiết, hệ điều hành không tổ chức tốt việc sử dụng tài nguyên dung chung các tiến trình hoạt động đồng thời, thì không không mang lại hiệu khai thác tài nguyên hệ thống mà còn làm hỏng liệu các ứng dụng Và nguy hiểm là việc hỏng liệu này có thể hệ điều hành và ứng dụng không thể phát Việc hỏng liệu ứng dụng có thể làm sai lệch ý nghĩa thiết kế nó Đây là điều mà hệ điều hành và người lập trình không mong muốn Các tiến trình hoạt động đồng thời thường cạnh tranh với việc sử dụng tài nguyên dùng chung Hai tiến trình hoạt động đồng thời cùng ghi vào không gian nhớ chung (một biến chung) trên nhớ hay hai tiến trình đồng thời cùng ghi liệu vào file chia sẻ, đó là biểu cạnh tranh việc sử dụng tìa nguyên dùng chung các tiến trình Để các tiến trình hoạt động đồng thời không cạnh tranh hay xung đột với sử dụng tài nguyên dùng chung hệ điều hành phải tổ chức cho các tiến trình này độc quyền truy xuất/sử dụng trên các tài nguyên dùng chung này Những tài nguyên hệ điều hành chia sẻ cho nhiều tiến trình hoạt động đồng thời dùng chung, mà có nguy dẫn đến tranh chấp các tiến trình này sử dụng chúng, gọi là tài nguyên găng Tài nguyên găng có thể là tài nguyên phần cứng tài nguyên phần mền, có thể là tài nguyên phân chia không phân chia được, đa số thường là tài nguyên phân chia là: các biến chung, các file chia sẻ (8) II.2.2 Đoạn găng (Critical Section) Đoạn code các tiến trình đồng thời, có tác động đến các tài nguyên có thể trở thành tài nguyên găng gọi là đoạn găng hay miền găng Tức là, các đoạn code các chương trình dùng để truy cập đến các vùng nhớ chia sẻ, các tập tin chia sẻ gọi là các đoạn găng Trong ví dụ trên có hai đoạn găng là: { L1 := Count và Count := L1 } Để hạn chế các lỗi có thể xảy sử dụng tài nguyên găng, hệ điều hành phải điều khiển các tiến trình cho, thời điểm có tiến trình nằm đoạn găng, có nhiều tiến trình cùng muốn vào (thực hiện) đoạn găng thì có tiến trình vào, các tiến trình khác phải chờ, tiến trình khỏi (kết thúc) đoạn găng phải báo cho hệ điều hành và/hoặc các tiến trình khác biết để các tiến trình này vào đoạn găng, vv Các công tác điều khiển tiến trình thực đoạn găng hệ điều hành gọi là điều độ tiến trình qua đoạn găng Để công tác điều độ tiến trình qua đoạn găng thành công, thì cần phải có phối hợp vi xử lý, hệ điều hành và người lập trình Vi xử lý đưa các thị, hệ điều hành cung cấp các công cụ để người lập trình xây dựng các sơ đồ điều độ hợp lý, để đảm bảo độc quyền việc sử dụng tài nguyên găng các tiến trình II.2.3 Yêu cầu đoạn găng Đoạn găng phải thỏa các yêu cầu sau : Tại thời điểm không thể có hai tiến trình nằm đoạn găng Nếu có nhiều tiến trình đồng thời cùng xin vào đoạn găng thì có tiến trình phép vào đoạn găng, các tiến trình khác phải xếp hàng chờ hàng đợi Tiến trình chờ ngoài đoạn găng không ngăn cản các tiến trình khác vào đoạn găng Không có tiến trình nào phép lâu vô hạn đoạn găng và không có tiến trình phải chờ lâu vào đoạn găng (chờ hàng đợi) Nếu tài nguyên găng giải phóng thì hệ điều hành có nhiệm vụ đánh thức các tiến trình hàng đợi để tạo điều kiện cho nó vào đoạn găng Các vấn đề có thể gặp phải đoạn găng Có thể dẫn đến tắc nghẽn (Deadlock) hệ thống Các tiến trình có thể bị đói (Stravation) tài nguyên II.3 Giải pháp Semaphore Semaphore là đóng góp quan trọng khác nhà toán học E W Dijkstra Có thể xem Semaphore là mở rộng Mutex locks Semaphore (sự đánh tín hiệu cờ) S là biến nguyên, khởi gán giá trị không âm, đó là khả phục vụ tài nguyên găng tương ứng với nó Ứng với S có hàng đợi F(s) để lưu các tiến trình bị blocked trên S Chỉ có hai thao tác Down và Up tác động đến semaphore (sự đánh tín hiệu cờ) S Down giảm S xuống đơn vị, Up tăng S lên đơn vị Mỗi tiến trình trước vào đoạn găng thì phải gọi Down để kiểm tra và xác lập quyền vào đoạn găng (9) Mỗi tiến trình sau khỏi đoạn găng phải gọi Up để kiểm tra xem có tiến trình nào đợi hàng đợi hay không, có thì đưa tiến trình hàng đợi vào đoạn găng Khi tiến trình gọi Up thì hệ thống thực Ở đây chúng ta cần lưu ý rằng: Down và Up là các thủ tục hệ điều hành, nên hệ điều hành đã cài đặt chế độc quyền cho nó, tức là các lệnh bên nó không thể tách rời II.4 Deadlock II.4.1 Giới thiệu vấn đề Trong môi truờng đa chương, nhiều quá trình có thể cạnh tranh số giới hạn tài nguyên Một quá trình yêu cầu tài nguyên, tài nguyên không sẳn dùng thời điểm đó, quá trình vào trạng thái chờ Quá trình chờ có thể không chuyển trạng thái trở lại vì tài nguyên chúng yêu cầu bị giữ quá trình chờ khác Trường hợp này gọi là deadlock (khoá chết) Trong trường hợp bài toán là tất các triết gia đói cùng lúc, họ ngồi vào bàn và tất cùng nhấc nĩa bên tay phải mình, và cùng chờ đợi nĩa từ hàng xóm bên tay trái dẫn đến các tiến trình bị khóa chết (10) II.4.2 Điều kiện hình thành tắt nghẽn Năm 1971, Coffman đã đưa và chứng tỏ rằng, hệ thống tồn đồng thời bốn điều kiện sau đây thì hệ thống xảy tắt nghẽn: Loại trừ lẫn (mutual excution) hay độc quyền sử dụng: Đối với các tài nguyên không phân chia thì thời điểm có tiến trình sử dụng tài nguyên Giữ và đợi (hold and wait): Một tiến trình chiếm giữ tài nguyên, lại xin cấp phát thêm tài nguyên Không ưu tiên (No preemption): Không có tài nguyên nào có thể giải phóng từ tiến trình chiếm giữ nó Sự tắc nghẽn có thể tồn với ba điều kiện trên, có thể không xảy với điều kiện đó Để chắn tắc nghẽn xảy cần phải có điều kiện thư tư Đợi vòng tròn (Circular wait): Đây là trường hợp ví dụ mà chúng ta đã nêu trên Tức là, tiến trình chiếm giữ tài nguyên mà tiến trình khác cần II.4.3 Ngăn chặn tắc nghẽn (Deadlock Prevention) Ngăn chặn tắc nghẽn là thiết kế hệ thống cho tượng tắc nghẽn bị loại trừ Các phương thức ngăn chặn tắc nghẽn tập trung giải bốn điều kiện gây tắc nghẽn, cho hệ thống không thể xảy đồng thời bốn điều kiện tắc nghẽn: Đối với điều kiện độc quyền: Điều kiện này gần không tránh khỏi, vì độc quyền là cần thiết tài nguyên thuộc loại phân chia các biến chung, các tập tin chia sẻ, hệ điều hành cần phải hỗ trợ độc quyền trên các tài nguyên này Đối với điều kiện giữ và đợi: Điều kiện này có thể ngăn chặn cách yêu cầu tiến trình yêu cầu tất tài nguyên mà nó cần thời điểm và tiến trình bị khoá (blocked) yêu cầu tài nguyên nó hệ điều hành đáp ứng Phương pháp này không hiệu Thứ nhất, tiến trình phải đợi khoảng thời gian dài để có đủ tài nguyên có thẻ chuyển sang hoạt động được, tiến trình cần số ít tài nguyên số đó là có thể hoạt động được, sau đó yêu cầu tiếp Thứ hai, lãng phí tài nguyên, vì có thể tiến trình nhiều tài nguyên mà đến kết thúc tiến trình sử dụng, và có thể đây là tài nguyên mà các tiến trình khác cần Ở đây hệ điều hành có thể tổ chức phân lớp tài nguyên hệ thống Theo đó tiến trình phải trả tài nguyên mức thấp cấp phát tài nguyên cấp cao Đối với điều kiện No preemption: Điều kiện này có thể ngăn chặn cách, tiến trình bị rơi vào trạng thái khoá, hệ điều hành có thể thu hồi tài nguyên tiến trình bị khoá để cấp phát cho tiến trình khác và cấp lại đầy đủ tài nguyên cho tiến trình tiến trình đưa khỏi trạng thái khoá Đối với điều kiện chờ đợi vòng tròn: Điều kiện này có thể ngăn chặn cách phân lớp tài nguyên hệ thống Theo đó, tiến trình cấp phát tài nguyên lớp L, thì sau đó nó có thể yêu cầu các tài nguyên lớp thấp lớp L (11) CHƯƠNG III CÁCH GIẢI QUYẾT BÀI TOÁN III.1 Quản lý vùng găng Chương trình xem triết gia là tiến trình, chopstick là tài nguyên chung cần bảo vệ Biến taken xây dựng class Chopstick để lý tài nguyên dùng chung là các chopsticks, chopsticks tạo có biến khóa taken để đánh dấu : taken = true chopstick đã sử dụng taken = false chopstick chưa sử dụng Class Chopstick đóng vai trò quản lý vùng găng với phương thức synchronized put() và get() để mở và đóng vùng găng synchronized void put() { taken=false; display.setChopstick(identity,taken); notify(); } Phương thức này tương ứng với hành động triết gia đặt Chopstick xuống (giải phóng Chopstick) để các triết gia khác có thể sử dụng tài nguyên chung này synchronized void get()throws java.lang.InterruptedException { while (taken) wait(); taken=true; display.setChopstick(identity,taken); } Nếu tài nguyên chung (Chopstick) sử dụng thì triết gia phải đợi (wait) tài nguyên giải phóng, lúc đó triết gia sử dụng tài nguyên này đồng thời thiết lập taken = true để khóa các tiến trình khác Như biến taken đóng vai trò khóa vùng tài nguyên dùng chung nó sử dụng tiến trình (12) Xét trường hợp cụ thể sau Chương trình tạo tiến trình tương ứng với triết gia và tài nguyên dùng chung tương ứng chopsticks public void start() { for (int i =0; i<display.NUMPHILS; ++i) chopstick[i] = new Chopstick(display,i); for (int i =0; i<display.NUMPHILS; ++i){ phil[i] = makePhilosopher(this,i, chopstick[(i-1+display.NUMPHILS)% display.NUMPHILS], chopstick[i]); phil[i].start(); } } Xét trạng thái cụ thể các chopsticks ta có chopsticks[0].taken == false chopsticks[1].taken == false chopsticks[2].taken == false chopsticks[3].taken == true chopsticks[4].taken == false (13) III.2 Giải pháp xử lý deadlock Vấn đề deadlock có thể tránh khỏi viêc xây dụng phương thức Wait() và Signal() cho vòng tròn đợi không xảy Ở đây các phương thức cài đặt sau public void Wait()throws java.lang.InterruptedException{ if(identity%2==0){ view.setPhil(identity,view.HUNGRY); right.get(); //gotright chopstick view.setPhil(identity,view.GOTRIGHT); sleep(500); left.get(); } else{ view.setPhil(identity,view.HUNGRY); left.get(); //gotleft chopstick view.setPhil(identity,view.GOTLEFT); sleep(500); right.get(); } } public void Signal(){ right.put(); left.put(); } Phương thức Wait() và Signal() xây dựng để quản lí tiến trình vào vùng găng Với cách xây dựng trên thì tiến trình cạnh có số thứ tự chẳn lẽ khác có thứ tự lấy các chopstick theo thứ tự khác III.3 Chương trình Chương trình xây dựng gồm class Class Diners : đây là class chính khởi tạo và liên kết các class khác Class PhilCanvas : quản lí giao diện Class Philosopher : class tạo các tiến trình Class Chopstick : tài nguyên dùng chung (chopstick ) (14) Các class quan hệ sơ đồ sau III.3.1 Class Philosopher Các biến cần xét private int indentity : dùng để đánh số (định id) cho tiến trình private Chopstick left, right : đây là tài nguyên dùng chung mà tiến trình phép sử dụng Phương thức Wait() và Signal() quản lí tiến trình vào vùng găng và giải vấn đề tắc nghẽn Phương thức run() : chạy tiến trình while (true) { view.setPhil(identity,view.THINKING); sleep(controller.sleepTime()); Wait(); view.setPhil(identity,view.EATING); sleep(controller.eatTime()); Signal(); } và tiến trình chờ đợi để vào vùng găng tiến trình gọi phương thức Wait() để kiểm tra điều kiện vào vùng găng và tiến trình thực thi thoát khỏi vùng găng và giải phóng tài nguyên (15) III.3.2 Class Chopstick Các biến cần xét private boolean taken : đánh dấu trạng thái chopstick đã sử dụng hay chưa, taken == true là tài nguyên đã sử dụng, taken == false chưa sử dụng private int indentity : định danh cho chopstick Phương thức get() gọi tiến trình muốn sử dụng tài nguyên Phương thức put() gọi để giải phóng tài nguyên III.3.3 Class Diner Khởi tạo giao diện, khởi tạo các tiến trình, tạo môi trường cho các tiến trình hoạt động III.3.4 Class PhilCanvas Quản lí giao diện (16) CHƯƠNG IV KẾT QUẢ CHƯƠNG TRÌNH IV.1.1 Chương trình tạm dừng Từ kết demo ta có : Triết gia số và số đói Triết gia sô và số suy nghĩ Triết gia số ăn (17) IV.1.2 Chương trình reset Khởi động lại các tiến trình tạm dừng, reset lại băng thông báo trạng thái (18) CHƯƠNG V KẾT LUẬN V.1.1 Đạt Chương trình đạt chức mô tả bài toán giao diện trực quan sinh động, sử dụng giao diện swing trên applet Tạo các tiến trình mô dựa trên lớp Thread Bằng cách sử dụng slider cho phép người dùng tùy chỉnh thời gian cung cấp cho các tiến trình, giúp dễ dàng nắm bắt và kiểm soát Bằng cách xây dựng phương thức Wait() chương trình đã xử lý vấn đề deadlock Chương trình phân thành các class với các chức rõ ràng tạo thuận lợi cho việc mở rộng và phát triển sau này, đặc biệt phát triển giao diện cách dễ dàng mà không ảnh hưởng đến phần lõi chương trình Chương trình có thể phát triển mở rộng cho n tiến trình tùy ý V.1.2 Chưa đạt Phần giao diện chương trình chưa bắt mắt (19) TÀI LIỆU THAM KHẢO [1] Đặng Vũ Tùng, Giáo trình Nguyên Lý Hệ Điều Hành, NXB Hà Nội(2005) [2] http://www.scribd.com/doc/7221635/H-iu-hanh?autodown=pdf [3] Đồ án mẫu khóa 05 (20) PHỤ LỤC //<APPLET CODE="Diners.class" WIDTH=400 HEIGHT=75 ALIGN=center> import java.awt.*; import java.awt.event.*; import java.applet.*; import java.awt.*; import java.awt.geom.AffineTransform; import javax.swing.*; public class Diners extends JApplet { PhilCanvas display; Thread[] phil= new Thread[PhilCanvas.NUMPHILS]; Chopstick[] chopstick = new Chopstick[PhilCanvas.NUMPHILS]; JScrollBar slider; JButton restart; JButton freeze; TextArea txtMes; public void init() { setLayout(new BorderLayout()); display = new PhilCanvas(this); display.setSize(300,320); add("Center",display); slider = new JScrollBar(Scrollbar.HORIZONTAL, 50, 5, 0, 100); restart = new JButton("Restart"); restart.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (display.deadlocked()) { stop(); slider.setValue(50); start(); } display.thaw(); } }); freeze = new JButton("Freeze"); freeze.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { display.freeze(); } }); (21) Panel p2 = new Panel(); p2.setLayout(null); p2.setSize(150,400); Label l0,l1,l2,l3,l4,l5,l6; l1 = new Label("EATING"); l2 = new Label(""); l2.setBackground(Color.GREEN); l3 = new Label("HUNGRY"); l4 = new Label(""); l4.setBackground(Color.BLUE); l5 = new Label("THINKING"); l6 = new Label(""); l6.setBackground(Color.YELLOW); l1.setBounds(10,220,60,30); p2.add(l1); l2.setBounds(80,220,50,30); p2.add(l2); l3.setBounds(10,260,60,30); p2.add(l3); l4.setBounds(80,260,50,30); p2.add(l4); l5.setBounds(10,300,60,30); p2.add(l5); l6.setBounds(80,300,50,30); p2.add(l6); p2.setBackground(Color.WHITE); txtMes = new TextArea(); txtMes.setBounds(0,0,150,200); p2.add(txtMes); Panel p1 = new Panel(); p1.setLayout(new BorderLayout()); p1.add("Center",slider); p1.add("East",restart); p1.add("West",freeze); add("South",p1); add("West",p2); setSize(600,400); } Thread makePhilosopher(Diners d, int id, Chopstick left, Chopstick right) { return new Philosopher(d,id,left,right); } public int sleepTime() { return (slider.getValue()*(int)(100*Math.random())); } (22) public int eatTime() { return (slider.getValue()*(int)(50*Math.random())); } public void start() { for (int i =0; i<display.NUMPHILS; ++i) chopstick[i] = new Chopstick(display,i); for (int i =0; i<display.NUMPHILS; ++i){ phil[i] = makePhilosopher(this,i, chopstick[(i-1+display.NUMPHILS)% display.NUMPHILS], chopstick[i]); phil[i].start(); } } public void stop() { for (int i =0; i<display.NUMPHILS; ++i) { phil[i].interrupt(); } } } class Philosopher extends Thread { private int identity; private PhilCanvas view; private Diners controller; private Chopstick left; private Chopstick right; Philosopher(Diners ctr, int id, Chopstick l, Chopstick r) { controller = ctr; view = ctr.display; identity = id; left = l; right = r; } public void Wait()throws java.lang.InterruptedException{ if(identity%2==0){ view.setPhil(identity,view.HUNGRY); right.get(); //gotright chopstick view.setPhil(identity,view.GOTRIGHT); sleep(500); left.get(); } (23) else{ view.setPhil(identity,view.HUNGRY); left.get(); //gotright chopstick view.setPhil(identity,view.GOTLEFT); sleep(500); right.get(); } } public void Signal(){ right.put(); left.put(); } public void run() { try { while (true) { //thinking view.setPhil(identity,view.THINKING); sleep(controller.sleepTime()); //hungry Wait(); //eating view.setPhil(identity,view.EATING); sleep(controller.eatTime()); Signal(); } } catch (java.lang.InterruptedException e) {} } } class Chopstick { private boolean taken=false; private PhilCanvas display; private int identity; Chopstick(PhilCanvas disp, int id){ display = disp; identity = id; } synchronized void put() { taken=false; display.setChopstick(identity,taken); (24) notify(); } synchronized void get()throws java.lang.InterruptedException { while (taken) wait(); taken=true; display.setChopstick(identity,taken); } } class PhilCanvas extends Canvas { Diners controller; Image offscreen; Dimension offscreensize; Graphics offgraphics; static final int NUMPHILS = 5; static final int THINKING = 0; static final int HUNGRY = 1; static final int GOTRIGHT = 2; static final int EATING =3; static final int GOTLEFT = 4; Image[] imgs = new Image[5]; AffineTransform [] philPlace = new AffineTransform[NUMPHILS]; int [] state = new int [NUMPHILS]; double [] chopX = new double[NUMPHILS]; double [] chopY = new double[NUMPHILS]; double [] disX = new double[NUMPHILS]; double [] disY = new double[NUMPHILS]; boolean[] untable= new boolean[NUMPHILS]; boolean frozen = false; String Message = ""; PhilCanvas(Diners controller) { super(); this.controller = controller; MediaTracker mt; mt = new MediaTracker(this); imgs[0] = controller.getImage(controller.getDocumentBase(), "image/thinking.gif"); mt.addImage(imgs[0], 0); imgs[1] = controller.getImage(controller.getDocumentBase(), "image/hungry.gif"); mt.addImage(imgs[1], 1); (25) imgs[2] = controller.getImage(controller.getDocumentBase(), "image/gotright.gif"); mt.addImage(imgs[2], 2); imgs[3] = controller.getImage(controller.getDocumentBase(), "image/eating.gif"); mt.addImage(imgs[3], 3); imgs[4] = controller.getImage(controller.getDocumentBase(), "image/gotleft.gif"); mt.addImage(imgs[4], 4); try { mt.waitForID(0); mt.waitForID(1); mt.waitForID(2); mt.waitForID(3); mt.waitForID(4); } catch (java.lang.InterruptedException e) { System.out.println("Couldn't load one of the images"); } initPlacing(); } void backdrop() { Dimension d = getSize(); if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) { offscreen = createImage(d.width, d.height); offscreensize = d; offgraphics = offscreen.getGraphics(); offgraphics.setFont(new Font("Helvetica",Font.BOLD,18)); Graphics2D g2D = (Graphics2D) offgraphics; g2D.translate(d.width/2, d.height/2); } offgraphics.setColor(Color.WHITE); offgraphics.fillRect(-d.width/2, -d.height/2, d.width, d.height); } void drawtable() { offgraphics.setColor(Color.red); offgraphics.fillOval(-80,-80,160,160); offgraphics.setColor(Color.black); for(int i=0; i<NUMPHILS; i++) { if(untable[i]){ offgraphics.setColor(Color.black); offgraphics.fillRect((int)chopX[i],(int)chopY[i],5,30); } (26) offgraphics.setColor(Color.black); offgraphics.drawString(String.valueOf(i),(int)disX[i],(int)disY[i]); offgraphics.setColor(Color.WHITE); offgraphics.fillOval((int)disX[i],(int)disY[i],25,25); } } public void paint(Graphics g) { update(g); } public void update(Graphics g) { backdrop(); for (int i = 0; i < NUMPHILS; i++) { philPaint(offgraphics,i); if(state[i]==EATING) Message += "Philosopher "+i+" EATING"; } controller.txtMes.setText(Message); drawtable(); if (deadlocked()) { offgraphics.setColor(Color.black); offgraphics.drawString("DEADLOCKED",-60,0); } g.drawImage(offscreen, 0, 0, null); } void philPaint(Graphics g,int i) { Graphics2D g2D = (Graphics2D)g; g2D.drawImage(imgs[state[i]],philPlace[i],this); } synchronized void setPhil(int id,int s) throws java.lang.InterruptedException{ while (frozen) wait(); state[id] = s; repaint(); } synchronized void freeze(){ frozen = true; } synchronized void thaw() { frozen = false; notifyAll(); Message = ""; (27) } synchronized void setChopstick(int id, boolean taken) { untable[id]= !taken; } boolean deadlocked(){ int i=0; while(i<NUMPHILS && state[i]==GOTRIGHT) ++i; return i==NUMPHILS; } void initPlacing() { double radius = 130.0; double philWidth = imgs[0].getWidth(this); double philHeight = imgs[0].getHeight(this); double radians; for (int i = 0; i < NUMPHILS; i++) { philPlace[i] = new AffineTransform(); radians = 2.0 * Math.PI*(1.0 - (double) i/(double)NUMPHILS); philPlace[i].rotate(radians); philPlace[i].translate(0,-radius); philPlace[i].translate(-philWidth/2,-philHeight/2); } radius = 55; for (int i = 0; i < NUMPHILS; i++) { radians = (double)i * 2.0 * Math.PI / (double)NUMPHILS + Math.PI/ (double)NUMPHILS; chopX[i] = -Math.sin(radians) * radius; chopY[i] = -Math.cos(radians) * radius; untable[i] = true; } radius = 65; for (int i = 0; i < NUMPHILS; i++) { radians = (double)i * 2.0 * Math.PI / (double)NUMPHILS; disX[i] = -Math.sin(radians) * radius-12; disY[i] = -Math.cos(radians) * radius-12; } } } (28)