Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 28 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
28
Dung lượng
888,74 KB
Nội dung
Báo cáo Đồ án Nguyên lý hệ điều hành LỜI NÓI ĐẦU Nguyên lý hệ điều hành môn học bổ ích giúp sinh viên chúng em hiểu biết cấu tổ chức, việc quản lý, điều phối tiến trình hệ thống máy tính Qua hiểu biết phần phần mềm máy tính hệ điều hành Việc nghiên cứu, hoàn thành đồ án nguyên lý hệ điều hành giúp chúng em hiểu rõ hệ điều hành Linux, hệ điều hành có nhiều tính vượt trội có triển vọng tương lai Chúng em xin chân thành cảm ơn hướng dẫn thầy Mai Văn Hà, tận tình dẫn giúp chúng em hoàn thành đề tài đồ án TỔNG QUAN ĐỀ TÀI 1.1 Bối cảnh đề tài: Nhận thấy việc giao tiếp c ác tiến trình linux có c ó thể t hể giúp ta t a hiểu rõ chế xử lý, trao đổi liệu tiến trình hệ điều hành linux Trong việc trao đổi liệu, giao tiếp qua đường ống pipe theo chế FIFO tương đối dễ hiểu phần giúp em hiểu nguyên lý tổ chức hệ điều hành nên chúng em định chọn đề tài 1.2 Mục tiêu đề tài: Hiểu việc giao tiếp tiến trình hệ điều hành linux đặc biệt đường ống pipe Nghiên cứu đề tài cho ta hiểu pipe chế hoạt động 1.3 Hƣớng giải quyết: Đầu tiên phải tìm hiểu cách giao tiếp tiến trình, tiến trình giao tiếp với thơng qua đường ống pipe Khi giao tiếp pipe vấn đề nảy sinh ( lỗi, hạn chế ) Từ tìm cách giải mơ cách sử dụng pipe thơng qua bài tốn Khi pipe thiết lập hai tiến trình, tiến trình ghi liệu vào pipe cịn tiến trình đọc liệu từ pipe SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Điều trước hết ta phải tạo hai tiến trình cha con, để hai tiến trình giao tiếp với ta phải tạo đường ống pipe Bây tìm hiểu tạo tiến trình giao tiếp với 1.4.Mơi trƣờng áp dụng: Chương trình mơ viết ngôn n gôn ngữ C chạy hệ điều hành linux để thấy chế c hế giao tiếp tiến trình thơng qua đường ống pipe Cộng đồng mã nguồn mở GNU cung cấp c ấp nhiều công cụ biên dịch C/C++ hệ điều hành Linux như: CodeBlock GCC G++ gdb GNU make GNU emacs trình) Bash Bison Trình biên dịc C/C++ Trình biên dịch C Trình biên dịch C++ Trình gỡ lỗi Trình quản lý mã nguồn trợ giúp biên dịch Trình soạn thảo văn (hỗ trợ cho việc sửa mã nguồn lập Hệ vỏ Shell hỗ trợ dịng lệnh hệ điều hành Bộ phân tích tương thích với yacc UNIX Trong đồ án mơn học này, n ày, em sử dụng trình biên dịch CodeBlock Code Block chạy chạy hệ điều hành linux Unbuntu 14.04 để áp dụng SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành CƠ SỞ LÝ THUYẾT 1.5.Giới thiệu hệ điều hành Linux 1.5.1 Lịch sử đời hệ điều hành Linux Vào năm 1991 Phần Lan, Linux B Torvalds lúc sinh viên trường Đại học tổng hợp Hensinki dùng máy tính cá nhân có trang bị xử lí 386 để nghiên cứu cách làm việc Do hệ điều hành MS-DOS khơng khai thác đầy đủ đặc tính xử lí 386, Linux sử dụng hệ điều hành thương mại khác Minix Hệ điều hành Minix hệ điều hành Unix cỡ nhỏ Do đối mặt với hạn chế hệ điều hành này, Linux bắt đầu viết lại số số phần mềm để thêm chức điểm đặc trưng Sau đó, ơng thơng báo kết miễn phí Internet tên gọi Linux – chữ viết tắt Linus Unix Phiên Linux 0.01 tung vào tháng 8/1991 Các phiên có nhiều hạn chế Tuy nhiên, kiện mã nguồn truyền bá rộng rãi giúp phát triển hệ điều hành nhanh Nhiều năm qua, số lượng công ty khai thác không ngừng tăng lên Ngày nay, Linux phát triển nhiều người rải rác khắp nơi giới Mặc dù phiên Linux tương đối không ổn định, phiên tuyên bố ổn định (1.0 ) công bố vào khoảng tháng 3/1994 Số phiên kèm với kernel có ý nghĩa đặc trưng liên quan đến chu kì phát triển Thực tế, trình phát triển Linux diễn theo chuỗi hai giai đoạn: Giai đoạn phát triển: kernel khơng có độ tin cậy cao tiến trình bổ sung chức cho nó, tối ưu hóa thử nghiệm ý tưởng Giai đoạn đem lại gia tăng số lượng phiên đánh số lẻ, chẳng hạn 1.1, 1.3… Đây thời điểm mà lượng công việc tối đa thực kernel Giai đoạn ổn định: mục đích tạo kernel ổn định tốt Trong trường hợp này, cho phép thực hiệu chỉnh, sửa đổi nhỏ Số phiên kernel gọi ổn định số chẵn, chẳng hạn 1.0 , 1.2 2.2 Ngày nay, Linux hồn tồn hệ điều hành Unix Nó ổn định liên tục phát triển Nó khơng có khả phát triển thiết bị ngoại vi thị trường ( nhớ flash quang , đĩa quang … ) mà hiệu cịn so sánh với số hệ điều hành Unix thương mại chí cịn có số điểm ưu việt Sau cùng, Linux có khoảng thời gian bị giới hạn mơi trường trường đại học, tiếp nhận hãng công nghiệp 1.5.2 Các chức hệ điều hành Linux Hệ điều hành Linux có nhiều chức chúng khai thác khả hệ Unix đại theo cách sau : Đa xử lí: đa xử lí thực nhiều chương trình đồng thời sử dụng hay nhiều xử lí SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Đa nền: Cho phép nhiều người sử dụng : giống tất hệ Unix, Linux cho phép nhiều người sử dụng làm việc máy thời điểm Hỗ trợ truyền thơng giao xử lí ( Pipes , IPC , Sockets ) Quản lí thơng điệp điều khiển khác nhau Hệ thống quản lí thiết bị đầu cuối tuân thủ theo tiêu chuẩn POSIX Linux giả thiết bị đầu cuối điều khiển trình Hỗ trợ dải rộng thiết bị ngoại vi, chẳng hạn card âm thanh, giao diện đồ hoa, mạng, giao diện hệ máy tính nhỏ … Buffer cache : vùng nhớ dành để làm vùng đệm cho đầu vào đầu từ trình khác Hệ thống quản lí nhớ trang yêu cầu Một trang khơng nạp chừng không thực cần thiết nhớ Các thư viện động dùng chung : Các thư viện động tải chúng thật cần thiết mã chúng dùng chung nhiều ứng dụng dùng chúng Các hệ thống file quản lí tốt đồng phân hoạch file Linux sử dụng bởi filesystem làm phân hoạch có định dạng khác ( MS-DOS , ISO9660, vv ) Thiết bị TCP/IP giao thức mạng khác 1.5.3 Hạn chế hệ điều hành Linux: Hiện hệ điều hành Linux hạn chế người sử dụng, chưa sử dụng cách rộng rãi Một phần có q phần mền tương thích với 1.6 Tiến trình Linux: Tiến trình chương trình xử lý, sở hữu trỏ lệnh, tập ghi biến Để hoàn thành tác vụ mình, tiến trình cần đến số tài nguyên – như CPU, nhớ chính, tập tin thiết bị nhập/xuất Cần phân biệt khái niệm chương trình tiến trình Một chương trình thực thể thụ động, chứa đựng thị điều khiển máy tính để tiến hành tác vụ Khi cho thực thị này, chương trình chuyển thành tiến trình, thực thể hoạt động, với trỏ lệnh xác định thị thi hành, kèm theo tập tài nguyên phục vụ cho hoạt động tiến trình Về mặt ý niệm, xem tiến trình sỡ hữu xử lý ảo cho riêng nó, thực tế, có xử lý thật chuyển đổi qua lại tiến trình Sự chuyển đổi nhanh chóng gọi là sự đa chương (multiprogramming) Hệ điều hành chịu trách nhiệm sử dụng thuật toán điều phối để định thời điểm cần dừng hoạt động tiến trình xử lý để phục vụ tiến trình khác, lựa chọn tiến trình phục vụ Bộ phận thực chức hệ điều hành gọi điều phối (scheduler) SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành 1.6.1 Các trạng thái tiến trình Trạng thái tiến trình thời điểm xác định hoạt động thời tiến trình thời điểm Trong q trình tồn tại, tiến trình thay đổi trạng thái nhiều nguyên nhân : phải chờ kiện xảy ra, hay đợi thao tác nhập/xuất hoàn tất, buộc phải dừng hoạt động hết thời gian xử lý … Tại thời điểm, tiến trình nhận trạng thái sau : I n execution ( thực ) : Tiến trình xử lý thực Ready ( sẵn sàng ): Tiến trình thực tiến trình khác lại chạy Suspended (chờ kích hoạt): Tiến trình chờ diễn kiện ( Ví dụ chờ nhập xuất kết thúc) Zombie (tồn tại) : Tiến trình kết thúc thực hiện, tham chiếu hệ thống Stop (ngừng) : Tiến trình bị treo tiến trình ngồi Các thay đổi trạng thái tiến trình trình bày sơ đồ trạng thái sau : Sự tạo Tín hiệu Ngừng Tín hiệu thành Sẵn sàng Lập lịch trình Kết thúc Nhập / Xuất Treo Đang thực Kết thúc Tồn Nhập / Xuất Sơ đồ trạng thái tiến trình Tại thời điểm, có tiến trình nhận trạng thái Thực bộ xử lý Trong đó, nhiều tiến trình trạng thái khác Các cung chuyển tiếp sơ đồ trạng thái biễu diễn chuyển trạng thái xảy điều kiện sau : - Tiến trình tạo đưa vào hệ thống - Bộ điều phối cấp phát cho tiến trình khoảng thời gian sử dụng CPU - Tiến trình kết thúc Hình : SVTH: Hồng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành - Tiến trình yêu cầu tài nguyên chưa đáp ứng tài nguyên chưa sẵn sàng để cấp phát thời điểm đó; tiến trình phải chờ kiện hay thao tác nhập/xuất - Bộ điều phối chọn tiến trình khác xử lý - Tài nguyên mà tiến trình yêu cầu trở nên sẵn sàng để cấp phát ; hay kiện thao tác nhập/xuất tiến trình đợi hồn tất 1.6.2 Cấu trúc tiến trình Một tiến trình đặc trưng nhiều thuộc tính hệ thống trì như: Trạng thái Định danh Các giá trị ghi, bao gồm đếm chương trình Mã định danh người sử dụng có tên mà tiến trình thực Thông tin kernel sử dụng để thiết lập lịch biểu tiến trình (thứ tự ưu tiên, v.v…) Thông tin không gian địa tiến trình ( phân đoạn mã, liệu, ngăn xếp) Thông tin nhập / xuất tiến trình thực ( mơ tả file mở, thư mục hành …) Tính tương thích thơng tin tổng kết tài ngun tiến trình sử dụng Ví dụ, có hai người dùng (user), mang tên A, mang tên B đăng nhập chạy chương trình C ( chương trình có nhiệm vụ tìm chuỗi ký tự file) đồng thời, thực tế hệ điều hành quản lý nạp mã chương trình C vào hai vùng nhớ khác gọi phân vùng tiến trình Hình cho thấy cách phân chia chương trình C thành hai tiến trình cho hai người dùng khác sử dụng Ở hình minh họa, người dùng A chạy chương trình C tìm chuỗi B tệp findgirl.txt $CB findA.txt Trong người dùng B chạy C tìm chuỗi A tệp findboy.txt $CA findB.txt Chúng ta nên nhớ hai người dùng A B hai máy tính khác đăng nhập vào máy chủ Linux gọi C chạy đồng thời Hình trạng khơng gian nhớ hệ điều hành Linux chạy chương trình C phục vụ người dùng SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Nếu dùng lệnh ps, hệ thống liệt kê cho bạn thơng tin tiến trình mà hệ điều hành kiểm sốt Ví dụ với tham số -af , thấy thơng tin ps liệt kê sau UID root root A PID 2345 4345 111 PPID 1234 2342 1235 C 0 STIME Apr11 pts/0 20:44 pts/3 20:44 tty1 TTY TIME 00:00:00 00:00:00 00:00:00 CMD [bash] ps – af CB 1235 20:44 tty1 00:00:00 CA find… B 222 find … Mỗi tiến trình gán cho định danh để nhận dạng gọi PID (process identifier) PID thường số nguyên dương có giá trị từ – 32768 Khi tiến trình yêu cầu khởi động, hệ điều hành chọn lấy số (chưa bị tiến trình chạy chiếm giữ) khoản số nguyên cấp phát cho tiến trình Khi tiến trình chấm dứt, hệ thống thu hồi lại số PID để cấp phát cho tiến trình Tiến trình với PID = tiến trình init, tiến trình init gọi chạy khởi động hệ điều hành, init tiến trình quản lý tạo tiến trình khác Chúng ta thấy lệnh ps – af hiển thị hai tiến trình A B với số PID 111 222 Mã lệnh thực thi lệnh C chứa tệp chương trình có sẵn đĩa hệ điều hành nạp vào nhớ Như thấy hình , tiến trình hệ điều hành phân chia rõ ràng : vùng chứa mã lệnh (code), vùng chứa liệu (data) Mã lệnh thường giống sử dụng chung Linux quản lý cho phép tiến trình chương trình sử dụng chung mã lệnh Thư viện Trừ thư viện đặc thù cịn thư viện chuẩn hệ điều hành cho phép chia sẻ dùng chung tiến trình hệ thống Việc chia sẻ thư viện, kích thước chương trình giảm đáng kể SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Trừ mã lệnh thư viện cịn liệu khơng thể chia sẻ tiến trình Mỗi tiến trình sở hữu phân đoạn liệu riêng ( ta thấy ở ví dụ trên) Mỗi tiến trình hệ thống dành riêng cho bảng mô tả file Bảng chứa số mô tả áp đặt cho file mở Và tiến trình có riêng ngăn xếp stack để lưu biến cục giá trị trả sau lời gọi hàm Tiến trình dành cho khoảng không gian dành riêng để lưu biến môi trường Cuối tiến trình hoạt động khơng gian địa ảo độc lập hệ thống cấp phát Chúng ta không cần quan tâm đến nhớ vật lý Linux UNIX có cách quản lý phân tran g cộng với hoán chuyển nhớ vật lý nhớ ảo thông qua phân vùng swap Bảng thơng tin tiến trình Hệ điều hành lưu cấu trúc danh sách bên hệ thống gọi bảng tiến trình(process table).Bảng tiến trình quản lý tất Pid hệ thống với thông tin chi tiết tiến trình chạy Ta xem bảng tiến trình với lệnh ps – af ( với tùy chọn –af để hiển thị chi tiết ) : UID root A PID 2345 111 PPID 1234 1235 C 0 STIME Apr11 20:44 222 1235 20:44 TTY pts/0 tty1 TIME 00:00:00 00:00:00 CMD [bash] CB tty1 00:00:00 CA find… B find … Trong : UID : tên người dùng gọi tiến trình PID : số định danh mà hệ thống cấp cho tiến trình ( dùng làm khóa đánh mục để truy xuất thông tin) PPID : parent PID số định danh tiến trình cha STIME : Thời điểm tiến trình đưa vào sử dụng TTY : Là hình terminal ảo nơi gọi thực thi tiến trình TIME : thời gian chiếm dụng CPU tiến trình CMD 1.6.3 : tồn dịng lệnh tiến trình triệu gọi Tạo lập tiến trình Ta gọi chương trình khác bên chương trình chạy hàm system() Hay nói cách khác ta tạo tiến trình từ tiến trình chạy Hàm system() khai báo sau : Hàm gọi chuỗi lệnh cmdstr thực thi chờ lệnh chấm dứt quay nơi gọi hàm #include int system( const char *cmdstr); SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Nó tương đương với việc ta gọi shell thực thi lệnh hệ thống system() trả mã lỗi 127 khởi động shell để gọi lệnh cmdstr Mã lỗi –1 gặp lỗi khác Ngược lại mã trả system() mã lỗi cmdstr sau thực thi trả Ví dụ cách sử dụng hàm system() chương trình: $sh –c cmdstr Ví dụ : system.c Hàm system() sử dụng để gọi lệnh “ ps – ax” hệ điều hành #include #include int main() { printf(“Running ps with system\n”); system(“ps –ax”); printf(“Done.\n”); exit(0); } Hàm system() cách đơn giản để ta triệu gọi chương trình n gồi khác Hay nói tạo tiến trình tách biệt với tiến trình ban đầu nơi gọi 1.6.4 Thay tiến trình hành với hàm exec Mỗi tiến trình hệ điều hành cấp cho không gian nhớ riêng biệt để tiến trình hoạt động Nếu tiến trình A gọi chương trình ngồi B (bằng hàm system() chẳng hạn) hệ điều hành thường thực thao tác : cấp phát khơng gian nhớ cho tiến trình mới, điều chỉnh lại danh sách tiến trình, nạp mã lệnh chương trình B đĩa vào khơng gian nhớ vừa cấp phát cho tiến trình Đưa tiến trình vào danh sách cần điều phối hệ điều hành Những cơng việc địi hỏi thời gian chiếm tài nguyên hệ thống Nếu tiến trình A chạy ta muốn tiến trình B khởi động chạy khơng gian nhớ cấp sẵn cho tiến trình A : Linux cung cấp cho ta tập hợp hàm exec() thực chức thú vị Hàm exec() thay toàn ảnh tiến trình A (bao gồm mã lệnh, liệu, bảng mơ tả file) thành ảnh tiến trình B hồn tồn khác Chỉ có số định danh PID tiến trình A giữ lại Hàm thay ảnh tiến trình bao gồm tập hàm sau : Đa số hàm yêu cầu bạn đối số path file đường dẫn đến chương trình cần #include extrn char **environ; int execl(const char *path, const char *arg,…); int execlp(const char *file, const char *arg…); int execle(const char *path, const char *arg,…,char int exect(const char *path, const char *argv[]); int execv(const char *path, const char *argv[]); int execvp(const char *path, const char *argv[]); *const envp[]); thực thi đĩa Arg đối số cần truyền cho chương trình thực thi, đối số tương tự cách ta gọi chương trình từ dịng lệnh SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành Ví dụ : exec.c Khi chạy chương trình lệnh ps thực thi, chương trình exec ta không chờ ps #include #include int main() { printf(“Running ps with exe clp\n”); execlp(“ps”, “ps”, “-ax”, 0); printf(“Done – But you never see this line”); exit(); } chấm dứt không in chuỗi Done Lý toàn mã lệnh khơng gian tiến trình exec sau gọi hàm execlp bị thay tiến trình ps 1.6.5 Nhân tiến trình với hàm fork() Tiến trình hành tạo tiến trình nhờ sử dụng lệnh gọi hệ thống fork() Nguyên bản làm nhân tiến trình hành> Được khai báo sau : #include #include pid_t fork(void); Khi fork gọi, tiến trình hành nhân : tuân thủ gốc, ngồi trừ định danh Tiến trình ban đầu gọi tiến trình cha tiến trình gọi tiến trình Ngồi PID ra, tiến trình mang thêm định danh PPID số định danh PID tiến trình cha Khởi tạo tiến trình Gọi fork() Trả PID tiến trình cha Mã lệnh tiến trình đầu (cha) Trả trị Mã lệnh thực thi tiến trình (con) Hình 3: Cơ chế phân chia tiến trình fork() SVTH: Hoàng Thị Mai Liên Trang 10 Báo cáo Đồ án Nguyên lý hệ điều hành Ống dẫn truyền thơng Tiến trình A Tiến trình B Hình 4: Truyền thơng hai tiến trình pipe Các pipe không cung cấp truyền thông theo cấu trúc Thao tác đọc độc lập với thao tác ghi cấp độ lệnh gọi hệ thống, người ta khơng thể biết kích cỡ, người gởi người nhận liệu chứa pipe Mặt khác, ưu điểm phương pháp truyền thông khả sử dụng liệu ghi nhiều lần để đọc lần Ta thấy rõ việc chuyển liệu Linux, ví dụ : $ps –ax | grep „runner‟ Lệnh trước hết thực lệnh ps – ax để liệt kê chi tiết danh sách tất tiến trình chạy hệ thống Kết tập liệu mà ps – ax trả sau chuyển cho lệnh grep thơng qua đường ống ( | ) Lệnh grep tiếp nhận liệu thực tìm chuỗi runner liệu ps gửi sang Kết tổ hợp lệnh có thơng tin tiến trình mang tên runner chạy in chi tiết 1.8.2 Đƣờng ống pipe giao tiếp trao đổi liệu chiều Hệ thống cung cấp cho ta hàm pipe() để tạo đường ống có khả đọc/ghi Sau đường ống tạo ra, ta dùng để giao tiếp hai tiến trình (thường tiến trình cha tiến trình sinh hàm fork()) Mỗi đường ống tạo kèm theo số mơ tả để ta truy xuất Hàm yêu cầu đối số mảng filedes bao gồm hai phần tử nguyên dùng để lưu #include int pipe(int filedes[2]) lại số mô tả cho đường ống trả sau lời gọi hàm Nếu hàm thành công ta dùng hai số mơ tả để thực thao tác đọc/ghi đường ống Phần tử thứ mảng dùng để đọc, phần tử thứ hai mảng dùng để ghi Ví dụ cách gọi hàm pipe() tạo đường ống Nếu pipe() thực thành công, đường ống tạo ra, pipes[0] số mô tả /* Trước hết định nghĩa mảng bao gồm hai phần tử để chứa số mô tả đường ống */ int pipes[2] /* Thực tạo đường ống pipe */ int rc = pipe (pipes); if (rc == -1) { /* tạo đường ống bị lỗi*/ perror(“pipe”); exit(1); } SVTH: Hoàng Thị Mai Liên Trang 14 Báo cáo Đồ án Nguyên lý hệ điều hành đường ống phía đầu đọc pipes[1] số mơ tả đường ống phía đầu ghi Nếu khơng tạo đường ống mã lỗi trả – 1 Trong ví dụ đây, sau tạo đường ống, ta gọi hàm fork() để tạo tiến trình Như ta biết, nhân đơi tiến trình, mơ tả file tiến trình cha tiến trình có khả kế thừa pipes[] mở tiến trình cha nhân bản chép sang tiến trình Tiến trình cha đọc liệu nhập vào từ phía người dùng ghi vào đường ống tiến trình phía bên đường ống tiếp nhận liệu cách đọc từ đường ống in hình Ví dụ : oneway_pipe.c #include #include /* hàm tiến trình */ void do_child(int data_pipe[]{ int c; /*chứa liệu đọc từ tiến trình cha*/ int rc; /*Lưu trạng thái trả read() */ /*Đóng đầu ghi, tiến trình khơng sử dụng*/ close(data_pipe[1]); /* Tiến trình sử dụng số mơ tả đường ống phía đầu đọc để đọc liệu chuyển đến từ tiến trình cha.*/ while ((rc=read(data_pipe[0],&c,1))>0){ putchar(c); } /*Dữ liệu đường ống đọc xong – thoát khỏi tiến trình con*/ exit(0); } /* Hàm xử lý cơng việc tiến trình cha*/ void do_parent(int data_pipe[]) { int c; /*Dữ liệu đọc người dùng nhập vào */ int rc; /*Lưu trị trả getchar()*/ /* Trước đóng đầu đọc khơng cần dùng đến*/ close(data_pipe[0]); /* Nhận liệu người dùng nhập ghi vào đường ống */ while ((c=getchar())>0) { /*ghi liệu vào đường ống */ if (rc == -1) { /* Dữ liệu bị lỗi */ perror(“Parent : pipe write error”); close (data_pipe[1]); exit(1); } } /* Đóng đường ống phía đầu ghi để thơng báo phía cuối đường ống liệu ghi hết */ close(data_pipe[1]); exit(0); } /* Chương trình chính*/ int main() { int data_pipe[2]; int pid; /* pid tiến trình con*/ int rc; /* lưu mã lỗi trả */ /*Tạo đường ống */ SVTH: Hoàng Thị Mai Liên Trang 15 Báo cáo Đồ án Nguyên lý hệ điều hành rc = pipe(data_pipe); if (rc == -1) { perror(“pipe create error”); exit(1); } /* Tách đôi tiến trình con*/ pid = fork(); switch (pid) { case –1 : perror (“fork error”); exit(1); case 0: do_child(data_pipe); default : doparent(data_pipe); } return 0; } Khi chạy chương trình, ta nhập liệu vào từ bàn phím, liệu nhận ghi trả lại tiến trình Chương trình thực chế trao đổi đường ống chiều Tiến trình cha chuyển liệu đến tiến trình cách ghi vào đường ống Tiến trình ngược lại đọc liệu để xử lý đầu bên đường ống Ở phát sinh nhu cầu trao đổi thông tin, liệu hai tiên trình Ta cần sử dụng hai đường ống song song Tiến trình dùng đường ống để đọc đường ống để ghi 1.8.3 Đƣờng ống pipe giao tiếp trao đổi liệu hai chiều Sử dụng chế đường ống giao tiếp hai chiều dễ dàng cho hai phía tiến trình cha tiến trình Tuy nhiên dễ gây tình trạng tắc nghẽn Đây trường hợp mà hai tiến trình trạng thái chờ đọc liệu khơng có tiến trình ghi vào đường ống Sau số trường hợp dẫn đến tắc nghẽn : - Cả hai đường ống rỗng Cả hai đường ống gọi hàm read() để đọc liệu Chúng trở nên tắc nghẽn Bởi đặc điểm hàm read() đọc liệu từ pipe theo chế : đường ống rỗng hàm khóa trạng thái chờ (block) liệu đổ vào đường ống hay đường ống bị đóng lại phía bên ghi - Tr ường hợp phức tạp Mỗi đường ống sử dụng đệm với kích thước giới hạn nhằm tăng tốc cho q trình đọc/ghi Khi tiến trình ghi vào đường ống, liệu đặt vào vùng đệm đường ống lấy phía đầu đọc Nếu vùng đệm này bị đầy, hàm write() hệ thống khóa chờ vùng đệm lấy bớt liệu Cách để lấy liệu khỏi vùng đệm phía đầu đọc phải gọi hàm read() Do đó, hai tiến trình ghi liệu vùng đệm tải khơng có bên đường ống thực đọc liệu ta rơi vào trạng thái tắc nghẽn SVTH: Hoàng Thị Mai Liên Trang 16 Báo cáo Đồ án Nguyên lý hệ điều hành 1.8.4 Pipe đặt tên Qua ví dụ ta thấy đường ống tạo truyền liệu hai tiến trình cha Tiến trình cha gọi fork() để chuyển giao gắn đường ống vào tiến trình con, tiến trình nhận liệu xử lý chuyển cho tiến trình cha Đường ống tạo hàm pipe() gọi đường ống vô danh Nó sử dụng tiến trình cha ta chủ động tạo hàm fork() Một vấn đề đặt là, hai tiến trình khơng có quan hệ với sử dụng chế pipe để giao tiếp với khơng? Câu trả lời có, Linux cho phép ta tạo đường ống đặt tên Những đường ống mang tên nhìn thấy truy xuất tiến trình khác * Tạo pipe đặt tên với hàm mkfifo() Đường ống đặt tên gọi với tên khác đối tượng FIFO Thật đường ống mang tên biểu diễn file hệ thống file Linux Ta dùng lệnh mkfifo để tạo file đường ống với tên định Trong chương trình, ta dùng hàm hệ thống mkfifo() hay mknod() Khai báo hàm mkfifo() : #include #include mkfifo(const char *filename, mode_t mode); Hàm mkfifo() yêu cầu hai đối số, đối số filename tên đường ống cần tạo, mode chế độ đọc ghi đường ống Việc tạo đường ống đặt tên không liên quan đến tiến trình Ta tạo pipe trước xây dựng chương trình sử dụng SVTH: Hồng Thị Mai Liên Trang 17 Báo cáo Đồ án Nguyên lý hệ điều hành CÀI ĐẶT THUẬT TỐN VÀ TRIỂN KHAI 1.9.Đề tài : Viết chương trình gốm trình Quá trình thứ cho người dùng nhập vào từ bàn phím chuỗi biểu diễn phép tính gồm phần tử +, -, (, ) Dộ ưu tiên phép tính ngoặc cao nhất, phép + – có độ ưu tiên Ví dụ : 1+7-(8-7+2) Sau truyền chuỗi liệu sang trình thứ Quá trình thứ thực tính tốn trả cho q trình thứ để thể cho người sử dụng biết 1.10 Mơ tả tốn : Chúng ta xây dựng chương trình đơn giản mơ giao tiếp tiến trình : tiến trình cha (P0) tiến trình con(P1) qua chế đường ống Tiến trình cha cho người dùng nhập vào chuỗi biểu thức cần tính lưu vào input_pipe Sau tiến trình đọc liệu từ input_pipe xử lí tính tốn kết chuỗi biểu thức, trả kết cho tiến trình cha thơng qua output_pipe Tiến trình cha lấy liệu từ output_pipe thị cho người dùng biết Các hàm,biến quan trọng sử dụng chương trình Dùng đường ống pipe : input_pipe output_pipe ParentProcess (int input[2], int output[2]) : Hàm bao gồm công việc mà tiến trình cha thực nhập chuỗi biểu thức từ bàn phím, ghi vào input_pipe ; đọc kết xử lý từ output_pipe nhằm thị cho người dùng biết ChildProcess(int input[2], int output[2]): Hàm bao gôm cơng việc mà tiến trình thực đọc liệu từ input_pipe, gọi hàm hauto() để xử lý liệu ghi liệu vào lại output_pipe Hauto(char* ch) : Hàm xử lí xâu biểu thức, phần tách thành dãy hậu tố, sau tính kết biểu thức ghi vào cuối chuỗi nhập AddChar(char* ch, char kt): Nối kí tự vào cuối xâu ch AddNumber(char *ch, int n): Đổi số thành kí tự nối vào cuối xâu ch inKt(char kt) : in kí tự inNumber(int n): in số SVTH: Hoàng Thị Mai Liên Trang 18 Báo cáo Đồ án Nguyên lý hệ điều hành Lựa chọn ngơn ngữ IDE: Chương trình code bẳng ngơn ngữ C Ubuntu, IDE sử dụng CodeBlock 1.11 Chƣơng trình: #include #include #include #include #include #include #include #include #include #include void void void void void void void bool void int ChildProcess(int input[2], int output[2]); ParentProcess(int input[2], int output[2]); xuly(char *ch); AddChar(char *ch, char kt); AddNumber(char *ch, int n); inKt(char kt); inNumber(int n); isOperator(char ch); errorBt(); isOther(int i); void { main(void) pid_t pid; int input_pipe[2]; int output_pipe[2]; int rc, child_status; rc = pipe(input_pipe); if(rc ==-1){ perror("\tmain : input_pipe error"); exit(1); } P1 xử lý biểu thức nhập vào rc = pipe(output_pipe); if(rc ==-1){ perror("\tmain : output_pipe error"); exit(1); } pid = fork(); if (pid == 0) ChildProcess(input_pipe, output_pipe); else{ //wait( &child_status ); ParentProcess(input_pipe, output_pipe); } SVTH: Hoàng Thị Mai Liên Trang 19 Báo cáo Đồ án Nguyên lý hệ điều hành } void { ChildProcess(int input[2], int output[2]) int rc; char ch[100] = ""; close(input[1]); close(output[0]); rc = read(input[0], &ch, 100); if (rc==-1) { perror("Error"); close(input[0]); close(input[1]); exit(1); } //Ham xu li bieu thuc vao xuly(ch); rc = write(output[1], ch, strlen(ch)); if (rc==-1) { perror("Error"); close(output[0]); close(output[1]); exit(1); } close(input[0]); close(output[1]); } void { ParentProcess(int input[2], int output[2]) int char rc; c, ch[100] = ""; close(input[0]); close(output[1]); printf("\n\tNhap bieu thuc: "); gets(ch); rc = write(input[1], ch, strlen(ch)); if (rc==-1) { perror("Error"); close(input[0]); close(input[1]); exit(1); } rc = read(output[0], ch, 100); if (rc==-1) { perror("Error"); SVTH: Hoàng Thị Mai Liên Trang 20 Báo cáo Đồ án Nguyên lý hệ điều hành close(output[0]); close(output[1]); exit(1); } close(input[1]); close(output[0]); } void xuly(char *ch){ char stack_[100] = "", kq[100] = "", tam[100]=""; int i = 0, j = -1, k = -1, temp = 0; /* i : chi so vong lap for j : chi so stack k : chi so chuoi hau to kq */ //Chuyen bieu thuc dang trung to sang hau to for( ; i=0 && (stack_[j]=='+' || stack_[j]=='-' || stack_[j]=='*' || stack_[j]=='/' || stack_[j]=='^' || stack_[j]=='a' || stack_[j]=='d') ) kq[++k] = stack_[j ]; stack_[++j] = ch[i]; } break; case '*': case '/': SVTH: Hoàng Thị Mai Liên Trang 21 Báo cáo Đồ án Nguyên lý hệ điều hành if( (k=0 && (stack_[j]=='*' || stack_[j]=='/' || stack_[j]=='^' || stack_[j]=='a' || stack_[j]=='d') ) kq[++k] = stack_[j ]; stack_[++j] = ch[i]; } break; case '^': if( k=0 && (stack_[j]=='^' || stack_[j]=='a' || stack_[j]=='d')) kq[++k] = stack_[j ]; stack_[++j] = ch[i]; } break; case '(': stack_[++j] = ch[i]; break; case ')': while(j>=0 && stack_[j]!= '(') kq[++k] = stack_[j ]; j ; break; default: if(isdigit(ch[i]) != 0){ temp = temp * 10 + ch[i] - 48; if(isdigit(ch[i+1])==0) { kq[++k] = temp; temp = 0; } } else i = isOther(i); } } while(j>=0){ kq[++k] = stack_[j ]; } printf("\n\tDang trung to: %s", ch); printf("\n\tDang hau to: "); for(i = 0; i =0 ; i ){ inKt(a[i]); } } SVTH: Hoàng Thị Mai Liên Trang 24 Báo cáo Đồ án Nguyên lý hệ điều hành bool isOperator(char ch){ switch(ch){ case '+': case '-': case '*': case '/': case '^': return true; default: return false; } } void errorBt(){ printf("\n Bieu thuc nhap vao khong dung, khong the tinh duoc!\n\n"); //exit(0); } int isOther(int i){ printf("\n\nisOther .\n\n"); return i; } int mu(int a, int b){ int i = 1, temp = 1; if(a==0) return 0; if(b==0) return 1; for( ; i