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
321,85 KB
Nội dung
Báo cáo Đồ án Nguyên lý hệ điều hành LỜI NĨI ĐẦU Ngun 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 tiến trình linux giúp ta 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 toá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 ngữ C chạy hệ điều hành linux để thấy chế giao tiếp tiến trình thơng qua đường ống pipe Cộng đồng mã nguồn mở GNU cung 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, em sử dụng trình biên dịch CodeBlock 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 hoàn toà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 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 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 – 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 đ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 Tín hiệu 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 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 : In 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 Tín hiệu 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 Kết thúc Các thay đổi trạng thái tiến trình trình bày sơ đồ trạng thái sau : Kết thúc Nhập / Xuất Sự tạo th Nhập / Xuất Hình : 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 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 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 nguyên 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 PID PPID C STIME TTY TIME CMD root 2345 1234 Apr11 pts/0 00:00:00 [bash] root 4345 2342 20:44 pts/3 00:00:00 ps –af A 111 1235 20:44 tty1 00:00:00 CB find… B 222 1235 20:44 tty1 00:00:00 CA 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 trang 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 PID PPID C STIME TTY TIME CMD root 2345 1234 Apr11 pts/0 00:00:00 [bash] A 111 1235 20:44 tty1 00:00:00 CB find… B 222 1235 20:44 tty1 00:00:00 CA find … Trong : CMD • • 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 : tồn dịng lệnh tiến trình triệu gọi 1.6.3 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 #include chờ lệnh chấm dứt quay nơi gọi hàm int system( const char *cmdstr); Nó tương đương với việc ta gọi shell thực thi lệnh hệ thống $sh –c cmdstr SVTH: Hoàng Thị Mai Liên Trang Báo cáo Đồ án Nguyên lý hệ điều hành 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: Ví dụ : system.c Hàm system() sử #include dụng để gọi lệnh “ps –ax” hệ #include int main() điều hành { Hàm system() cách đơn printf(“Running ps with system\n”); giản để ta triệu gọi system(“ps –ax”); printf(“Done.\n”); chương trình ngồi khác Hay exit(0); 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 #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[]); 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 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 Ví dụ : exec.c Khi chạy chương trình #include lệnh ps thực thi, chương #include int main() trình exec ta khơng chờ ps { chấm dứt không bao printf(“Running ps with execlp\n”); in chuỗi Done Lý execlp(“ps”, “ps”, “-ax”, 0); printf(“Done – But you never see this line”); exit(); SVTH: Hoàng Thị Mai Liên } Trang Báo cáo Đồ án Nguyên lý hệ điều hành 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 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, 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 cịn 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 Trả trị Mã lệnh tiến trình đầu (cha) Mã lệnh thực thi tiến trình (con) Hình 3: Cơ chế phân chia tiến trình fork() Trường hợp khơng tách được, fork() trả trị -1 Kiểu pid_t khai báo định danh unistd.h kiểu nguyên(int) Cả hai tiến trình hoạt động đồng thời xen Ví dụ cho cách sử dụng hàm fork() để nhân đơi tiến trình: SVTH: Hoàng Thị Mai Liên Trang 10 Báo cáo Đồ án Nguyên lý hệ điều hành 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 #include int pipe(int filedes[2]) gồm hai phần tử nguyên dùng để lưu 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); } đườ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 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[]{ SVTH: Hồng Thị Mai Liên Trang 14 Báo cáo Đồ án Nguyên lý hệ điều hành 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 – 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 */ 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; SVTH: Hoàng Thị Mai Liên Trang 15 Báo cáo Đồ án Nguyên lý hệ điều hành } 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 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 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 q 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 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 SVTH: Hoàng Thị Mai Liên Trang 16 Báo cáo Đồ án Nguyên lý hệ điều hành 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: Hoà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 TOÁ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ố 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 SVTH: Hoàng Thị Mai Liên Trang 18 Báo cáo Đồ án Nguyên lý hệ điều hành 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); } 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 P1 xử lý biểu thức nhập vào 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); } } void { close(input[0]); close(output[1]); 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"); close(output[0]); close(output[1]); exit(1); SVTH: Hoàng Thị Mai Liên Trang 20 Báo cáo Đồ án Nguyên lý hệ điều hành } 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 '/': 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]); } bool isOperator(char ch){ switch(ch){ SVTH: Hoàng Thị Mai Liên Trang 24 Báo cáo Đồ án Nguyên lý hệ điều hành 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