TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI KHOA CÔNG NGHỆ THÔNG TIN BÀI TẬP LỚN MÔN HỌC NGUYÊN LÝ HỆ ĐIỀU HÀNH ĐỀ TÀI Nghiên cứu tìm hiểu về quản lý tiến trình trong HĐH Linux Giảng Viên Ths Nguyễn Tuấn Tú Nhóm Số Nhóm 2 Lớp IT6025 6(006)K15 HÀ NỘI, 2022 TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI KHOA CÔNG NGHỆ THÔNG TIN BÀI TẬP LỚN MÔN HỌC NGUYÊN LÝ HỆ ĐIỀU HÀNH ĐỀ TÀI Nghiên cứu tìm hiểu về quản lý tiến trình trong HĐH Linux Giảng Viên Ths Nguyễn Tuấn Tú Lớp IT6025 6(006)K15 HÀ NỘI, 2022 MỤC LỤC Trang Chương 1.
GIỚI THIỆU VỀ HỆ ĐIỀU HÀNH LINUX
Tổng quan về hệ điều hành
1.1.1 Khái niệm hệ điều hành
Hệ điều hành là phần mềm hệ thống quan trọng, quản lý thiết bị phần cứng và tài nguyên phần mềm trên máy tính Nó đóng vai trò trung gian giữa người sử dụng và phần cứng, tạo ra môi trường thuận lợi cho việc phát triển và thực hiện ứng dụng Khi khởi động máy tính, hệ điều hành được khởi động đầu tiên, cho phép người sử dụng truy cập các chương trình ứng dụng thông qua giao diện tương tác mà hệ điều hành cung cấp.
Nhiệm vụ cơ bản của hệ điều hành
Điều khiển vò quỏn lí trực tiếp các phần cứng.
Thực hiện các thao tác cơ bản trên máy tính như đọc và viết tập tin, quản lý hệ thống tập tin cùng với các kho dữ liệu là rất quan trọng Những kỹ năng này giúp người dùng tối ưu hóa quy trình làm việc và nâng cao hiệu quả sử dụng máy tính.
Hệ thống giao diện sơ khai cho ứng dụng được cung cấp thông qua một thư viện các hàm chuẩn, cho phép điều hành các phần cứng mà các ứng dụng có thể truy cập và gọi đến.
Cung cấp một hệ thống lệnh cơ bản để điều hành máy Các lện này gọi là lệnh hệ thống (system command).
Hệ điều hành cung cấp các phần mềm ứng dụng cơ bản, bao gồm trình duyệt web, chương trình soạn thảo văn bản, ứng dụng nghe nhạc và phần mềm chỉnh sửa ảnh.
1.1.2 Các thành phần cơ bản của hệ điều hành
Hệ thống quản lí tiến trình: Tạo và hủy các tiến trình; lập lịch thực hiện các tiến trình
Hệ thống quản lý bộ nhớ chính đóng vai trò quan trọng trong việc lưu giữ thông tin về các vị trí trong bộ nhớ, quyết định quá trình nào sẽ được nạp vào bộ nhớ chính và thực hiện việc cấp phát cũng như thu hồi bộ nhớ khi cần thiết.
Hệ thống quản lí bộ nhớ phụ: Quản lí các vùng trống trên đĩa, định vị, lưu trữ, lập lịch cho đĩa
Hệ thống quản lí nhập xuất: Cung cấp cơ chế làm việc thân thiện, dễ thao tác hơn, che dấu đi những đặc thù của phần cứng
Hệ thống quản lí tập tin: Hỗ trợ thao tác với tập tin như tạo, xóa, khôi phục, ánh xạ tập tin trên hệ thống phụ.
Hệ thống bảo vệ: Kiểm soát quá trình truy suất của chương trình, tiến trình hoặc người sử dụng với tài nguyên hệ thống
Hệ thống dịch lệnh: Đọc và thông dịch các lệnh điều khiển
1.1.3 Phân loại hệ điều hành
Hệ điều hành đơn nhiệm một người sử dụng:
Là hệ điều hành chỉ cho phép tại một thời điểm chỉ có một chương trình được thực thi, các chương trình phải thực hiện lần lượt
Hệ điều hành đa nhiệm một người sử dụng:
Cho phép một người đăng nhập vào hệ thống nhưng có thể kích hoạt cho hệ thống thực hiện nhiều chương trình
Hệ điều hành đa nhiệm nhiều người sử dụng:
Hệ thống cho phép nhiều người dùng đăng nhập cùng lúc và thực hiện nhiều chương trình một cách đồng thời Để đáp ứng yêu cầu này, máy tính cần được trang bị bộ xử lý mạnh mẽ và dung lượng bộ nhớ trong lớn.
Hệ điều hành linux
Năm 1991, Linus Torvalds, khi còn là sinh viên tại đại học Helsinki, đã nảy ra ý tưởng phát triển một hệ điều hành mới nhằm thay thế cho hệ điều hành cũ kỹ trong giáo dục Từ đó, ông đã bắt đầu viết những dòng lệnh đầu tiên của Linux, đánh dấu sự khởi đầu cho sự phát triển mạnh mẽ của hệ điều hành này.
Hình 1.1 Linus Torvalds – Cha đẻ của hệ điều hành Linux
Ngày nay, Linux được phân ra làm nhiều nhánh như: Ubuntu, Linux Mint, Fedora… nhưng thông dụng nhất hiện nay đang là Ubuntu. Ưu điểm
Hiện nay, ở Việt Nam nói riêng thì tỷ lệ người sử dụng Windows lậu đang chiếm con số rất cao
Linux có lợi thế nổi bật nhờ vào việc là nền tảng mã nguồn mở và miễn phí Trong khi người dùng phải chi hàng triệu đồng cho Windows bản quyền và bộ Microsoft Office, thì với Linux, bạn hoàn toàn có thể sử dụng mà không tốn một xu nào, cùng với các ứng dụng văn phòng miễn phí như OpenOffice và LibreOffice.
Khi sử dụng Linux, bạn sẽ không phải lo lắng về virus hay mã độc như trên Windows, vì chúng không thể hoạt động trên nền tảng này Công việc của bạn chỉ cần xóa chúng khi phát hiện trên USB hoặc ổ cứng di động.
Trên hệ điều hành Linux, người dùng có thể tự do chỉnh sửa và tùy biến theo ý muốn, trong khi trên Windows, việc này cần có sự chấp thuận từ Microsoft Ngoài ra, Linux cung cấp khả năng tương thích với nhiều môi trường khác nhau, tạo ra một nền tảng lý tưởng cho lập trình viên và nhà phát triển.
Hoạt động mượt mà trên các máy tính có cấu hình yếu
Khi Microsoft phát hành bản nâng cấp mới cho Windows, yêu cầu về phần cứng thường tăng lên Nếu laptop không đáp ứng đủ cấu hình, người dùng sẽ không thể nâng cấp và phải tiếp tục sử dụng phiên bản cũ, dẫn đến việc không nhận được các bản cập nhật từ Microsoft.
Hệ điều hành Linux hoạt động mượt mà và ổn định trên các máy tính có cấu hình thấp, không cần nâng cấp phần cứng Ngoài ra, Linux còn được hỗ trợ và nâng cấp thường xuyên bởi cộng đồng lập trình viên.
Mặc dù Linux có nhiều ưu điểm nổi bật, nhưng vẫn tồn tại một số nhược điểm đáng chú ý Chính những hạn chế này có thể là lý do khiến Windows ngày càng chiếm ưu thế trên thị trường.
Số lượng ứng dụng hỗ trợ trên Linux còn rất hạn chế.
Một số nhà sản xuất không phát triển driver hỗ trợ nền tảng Linux.
Khó làm quen, đặc biệt nếu bạn đã quá quen thuộc với Windows thì khi chuyển sang Linux, bạn sẽ cần một khoảng thời gian để làm quen nó.
KHÁI NIỆM VỀ TIẾN TRÌNH
Khái niệm về tiến trình
Tiến trình là một khái niệm cơ bản trong mọi hệ điều hành, định nghĩa là thực thể của chương trình đang hoạt động trong hệ thống Ví dụ, một web server hoặc một chương trình soạn thảo văn bản đang chạy trên thiết bị đều được coi là tiến trình.
Một tiến trình tương tự như con người, trải qua các giai đoạn từ khi ra đời cho đến khi kết thúc Nó có thể có cuộc đời với nhiều hoặc ít ý nghĩa, và khả năng sinh ra một hoặc nhiều tiến trình con Tuy nhiên, điểm khác biệt là tiến trình không có giới tính và chỉ có một tiến trình cha duy nhất.
Khi một tiến trình con được tạo, nó gần như giống hệt tiến trình cha, bao gồm việc sao chép toàn bộ không gian địa chỉ và thực thi mã nguồn tương tự Tiến trình con sẽ bắt đầu chạy mã nguồn riêng từ thời điểm gọi hàm tạo tiến trình mới.
Mặc dù tiến trình cha và tiến trình con cùng sử dụng mã nguồn chung, nhưng chúng sở hữu các phần dữ liệu tách biệt, bao gồm stack và heap Điều này đảm bảo rằng mọi thay đổi dữ liệu trong tiến trình con sẽ không tác động đến dữ liệu của tiến trình cha.
Tiến trình trong hệ điều hành linux
Trong hệ điều hành Linux, tiến trình được chia thành hai loại: tiến trình cha (parent process) và tiến trình con (child process) Khi một tiến trình thực hiện lệnh fork() để tạo ra một tiến trình mới, tiến trình đó được gọi là tiến trình cha, trong khi tiến trình mới được tạo ra được gọi là tiến trình con.
Hình 2.1 Sơ đồ tiến trình trong hệ điều hành linux
Mỗi tiến trình (process) có thể có nhiều tiến trình con (child process), nhưng mỗi tiến trình con chỉ thuộc về một tiến trình cha (parents process) Khi xem xét thông tin của một tiến trình, ngoài PID (Process ID), chúng ta cần chú ý đến PPID (Parent Process ID), vì nó cung cấp thông tin về tiến trình cha của tiến trình đó.
CÁC TRẠNG THÁI CỦA MỘT TIẾN TRÌNH
Trạng thái của một tiến trình tại một thời điểm cụ thể được xác định bởi các hoạt động hiện tại của nó Trong quá trình hoạt động, tiến trình có thể thay đổi trạng thái do nhiều nguyên nhân, chẳng hạn như phải chờ một sự kiện xảy ra, đợi thao tác nhập xuất hoàn tất, hoặc bị buộc dừng do hết thời gian xử lý.
Hình 3.1: Các trạng thái của một tiến trình
Tiến trình mới được đưa vào hàng đợi với trạng thái "mới khởi tạo" Trong giai đoạn này, hệ điều hành đã tạo ra thông tin cần thiết cho tiến trình, nhưng tiến trình vẫn chưa được thêm vào danh sách các tiến trình có thể thực hiện Thông thường, tiến trình ở trạng thái này chưa được lưu trữ trong bộ nhớ.
- Ready(sẵn sàng): Chương trinh đưa vào hàng đợi ở trạng thái sẵn sàng được thi hành.
- Waiting(chờ đợi): Tiến trình được đưa vào trạng thái chờ
- Running(chạy): Tiến trình được thi hành
Halt (kết thúc) là trạng thái mà tiến trình ngừng hoạt động và không còn nằm trong danh sách các tiến trình đang thực hiện Tuy nhiên, tiến trình này vẫn chưa bị xóa hoàn toàn Một tiến trình sẽ chuyển sang trạng thái Halt sau khi hoàn thành nhiệm vụ của mình hoặc bị một tiến trình khác kết thúc.
Hệ thống ghi nhận các trạng thái của tiến trình thông qua khối mô tả tiến trình.
Khối mô tả tiến trình bao gốm các thành phần:
+ Con trỏ trạng thái của tiến trình (Cho biết trạng thái hiện tại của tiến trình).
+ Vùng lưu trữ giá trị các thanh ghi mà tiến trình đang sử dụng.
+ Số thứ tự của tiến trình.
+ Thông tin về tài nguyên tiến trình đang sử dụng hoặc được phép sử dụng.
QUAN HỆ GIỮA CÁC TIẾN TRÌNH
Tiến trình độc lập
Tiến trình được coi là độc lập khi hoạt động của nó không tác động đến các tiến trình khác trong hệ thống và ngược lại Các tiến trình độc lập thường có những đặc điểm riêng biệt giúp chúng hoạt động một cách hiệu quả mà không bị ảnh hưởng lẫn nhau.
+ Trạng thái của nó không bị chia sẻ với bất kỳ tiến trình nào.
+ Việc thực hiện tiến trình là đơn định (Kết quả của tiến trình phụ thuộc vào đầu vào).
+ Tiến trình có thể được lặp lại.
+ Tiến trình có thể bị dừng hoặc bắt đầu lại mà không gây ảnh hưởng tới các tiến trình khác (Sự cố bất thường xảy ra trong hệ thống).
Tiến trình song song
Tiến trình được gọi là song song nếu hoạt động của nó ảnh hưởng tới các tiến trình khác đang hoạt động trong hệ thống.
Tiến trình song song được chia thành nhiều loại:
Tiến trình song song độc lập là các tiến trình hoạt động đồng thời mà không tương tác hay chia sẻ thông tin với nhau Để đảm bảo an toàn cho dữ liệu của các tiến trình này, hệ điều hành cần thiết lập cơ chế bảo vệ hiệu quả và phân bổ tài nguyên một cách hợp lý.
Trong tiến trình song song, các tiến trình A và B có mối quan hệ thông tin khi chúng trao đổi thông tin với nhau Cụ thể, hai tiến trình này được xem là có quan hệ thông tin nếu tiến trình A gửi thông báo cho tiến trình B hoặc ngược lại.
Tiến trình song song phân cấp là quá trình trong đó một tiến trình có khả năng khởi tạo các tiến trình khác hoạt động đồng thời Tiến trình khởi tạo được gọi là tiến trình cha, trong khi các tiến trình được tạo ra được gọi là tiến trình con.
Tiến trình song song đồng mức là các tiến trình hoạt động đồng thời, chia sẻ tài nguyên theo nguyên tắc lần lượt Mỗi tiến trình, sau khi sử dụng tài nguyên trong một khoảng thời gian nhất định, cần tự động trả lại tài nguyên cho tiến trình khác Các đặc trưng của tiến trình song song này bao gồm việc quản lý tài nguyên hiệu quả và đảm bảo tính công bằng trong việc sử dụng.
+ Trạng thái của nó bị chia sẻ cho các tiến trình khác.
+ Việc thực hiện tiến trình không đơn điệu (Kết quả của tiến trình phụ thuộc vào dãy thực hiện tương ứng và không dự báo trước).
+ Việc thực hiện tiến trình không đơn định (Kết quả của tiến trình không giống nhau với cùng một giá trị đầu vào).
Quản lý tiến trình trên Linux
Tại sao phải quản lý tiến trình
* Nhiệm vụ của quản lý tiến trình :
- Tạo lập, hủy bỏ tiến trình
- Tạm dừng, tái kích hoạt tiến trình
- Tạo cơ chế thông tin liên lạc giữa các tiến trình
- Tạo cơ chế đồng bộ hóa giữa các tiến trình
- Hạn chế tối đa xung đột và bế tắc xảy ra, đưa ra giải pháp nếu xảy ra các tình huống đó.
- Tận dụng tối đa khả năng của CPU (bài toán lập lịch).
Tiến trình là môi trường thực hiện bao gồm phân đoạn lệnh và phân đoạn dữ liệu, khác với chương trình chỉ là tập hợp lệnh Trên hệ điều hành Linux, tiến trình được xác định qua số hiệu pid và có thể thuộc nhóm, được phân biệt bằng số hiệu nhóm PRGP Một số hàm C cho phép lấy thông số của tiến trình như sau: `int getpid()` trả về pid của tiến trình hiện tại, `int getppid()` trả về pid của tiến trình cha, `int getpgrp()` trả về số hiệu nhóm tiến trình, và `int setpgrp()` tạo ra số hiệu nhóm tiến trình mới.
Lệnh : printf("Toi la tien trinh %d thuoc nhom %d",getpid(),getgrp());Kết quả sẽ là: Toi là tien trinh 235 thuoc nhom 231
Các loại tiến trình chính trên Linux
Tiến trình với đối thoại (Interactive processes): là tiến trình khởi động và quản lý bởi shell, kể cả tiến trình foreground hoặc background.
Tiến trình batch (Batch processes): Tiến trình không gắn liền đến bàn điều khiển (terminal) và được nằm trong hàng đợi để lần lượt thực hiện
Tiến trình ẩn trên bộ nhớ, hay còn gọi là daemon processes, là các tiến trình hoạt động trong nền Hầu hết các server cung cấp dịch vụ chạy theo phương thức này, cho phép các chương trình chờ đợi các yêu cầu từ client để phản hồi qua các cổng xác định Các dịch vụ Internet phổ biến như email, web, và DNS đều hoạt động dựa trên nguyên tắc này Các chương trình này thường được gọi là daemon và tên của chúng thường kết thúc bằng ký tự đặc biệt.
Tạo một tiến trình
Hàm fork() trong lập trình tạo ra một tiến trình con, với giá trị trả về là 0 cho tiến trình con và PID cho tiến trình cha Nếu không thể tạo tiến trình mới, giá trị trả về sẽ là -1 Cả tiến trình con và cha sẽ chia sẻ cùng đoạn mã, trong khi đoạn dữ liệu của tiến trình con là một bản sao chính xác từ tiến trình cha Tuy nhiên, tiến trình con vẫn có những khác biệt như PID và thời gian xử lý.
Dừng một tiến trình
Lệnh kill thường được sử dụng để ngừng thi hành một tiến trình dựa trên định danh của tiến trình PID :
Signal : là một số hay tên của tín hiệu được gửi tới tiến trình.
PID : mã số nhận diện tiến trình muốn dừng.
Lệnh killall: dùng để kết thúc tất cả các tiến trình của một câu lệnh thông qua việc truyền tên của câu lệnh dưới dạng một tham số:
Người dùng thông thường có thể chấm dứt các tiến trình của riêng họ, nhưng không phải các tiến trình thuộc về người dùng khác
Lệnh kill cho phép gửi bất kỳ tín hiệu nào tới một tiến trình, nhưng mặc định sẽ gửi tín hiệu 15 (TERM) để kết thúc chương trình Một số tín hiệu thường được sử dụng với lệnh kill bao gồm.
SIGHUP 1 - Hangup (gọi lại tiến trình).
SIGINT 2 - Ngắt từ bàn phím (Ctrl+C).
SIGTERM 15 - Kết thúc tiến trình.
Khi hoàn tất một tiến trình hoặc chuỗi tiến trình, nên ưu tiên sử dụng tín hiệu SIGTERM để thử kết thúc, vì đây là tín hiệu ít gây nguy hiểm nhất Nếu tiến trình không phản hồi, mới nên chuyển sang sử dụng tín hiệu INT hoặc KILL.
Giao tiếp giữa các tiến trình
Giao tiếp giữa các tiến trình được thực hiện thông qua các tín hiệu chuẩn của hệ thống, giúp báo hiệu các sự kiện không đồng bộ cho một hoặc nhiều tiến trình Mỗi tín hiệu có thể kết hợp với bộ xử lý tín hiệu, làm gián đoạn quá trình xử lý của tiến trình và yêu cầu hệ thống gọi bộ xử lý tín hiệu ngay lập tức Sau khi xử lý tín hiệu hoàn tất, tiến trình sẽ tiếp tục thực thi bình thường.
5.5.1 Gửi tín hiệu đến tiến trình a Các nguồn gửi signals:
* Từ phần cứng (ví dụ lỗi do các phép tính số học)
Khi xảy ra một số điều kiện về phần cứng (SIGSEGV, SIGFPE)
Khi xảy ra điều kiện phần mềm (SIGIO)
* Từ người dùng đầu cuối
Trong hệ thống quản lý tiến trình, việc gửi tín hiệu từ một tiến trình này đến một tiến trình khác là rất quan trọng, chẳng hạn như khi tiến trình cha yêu cầu tiến trình con kết thúc Có nhiều phương pháp để gửi tín hiệu đến tiến trình, cho phép các tiến trình tương tác và quản lý lẫn nhau hiệu quả hơn.
Ctrl+C: gửi tín hiệu INT( SIGINT ) đến tiến trình, ngắt ngay tiến trình
Ctrl+Z: gửi tín hiệu TSTP( SIGTSTP ) đến tiến trình, dừng tiến trình
Ctrl+/: gửi tín hiệu ABRT( SIGABRT ) đến tiến trình, kết thúc ngay tiến trình
Lệnh kill được sử dụng để ngừng một tiến trình đang hoạt động Mặc định, lệnh này gửi tín hiệu 15 (TERM) để kết thúc chương trình, nhưng người dùng có thể gửi bất kỳ tín hiệu nào khác tới tiến trình bằng cú pháp: kill - .
Ví dụ: kill -INT 2309 hoặc kill -2 2309 dùng gửi tín hiệu INT ngắt tiến trình có PID 2309.
Nếu không chỉ định tên tín hiệu, tín hiệu TERM được gửi để kết thúc tiến trình.
Lệnh fg: gửi tín hiệu CONT đến tiến trình, dùng đánh thức các tiến trình tạm dừng do tín hiệu TSTP trước đó.
Bằng các hàm hệ thống kill():
#include int main(void){ pid_t retVal; retVal = fork(); if(retVal > 0){ int i = 0; while(i++ < 5){ printf("in the parent process.\n"); sleep(1);
//hủy tiến trình con kill(retVal, SIGKILL);
//Không vượt quá 15, vì tiến trình cha sẽ hủy nó while(i++ < 15){ printf("In the child process.\n"); sleep(1);
18 printf("Something bad happened."); exit(EXIT_FAILURE);
5.5.2 Nhận và xử lí tín hiệu : a Khi một tiến trình nhận một tín hiệu, nó có thể xử sự theo một trong các cách sau :
- Xử lý tín hiệu theo kiểu mặc định
- Tiếp nhận tín hiệu và xử lý theo cách đặc biệt của tiến trình. b Bộ xử lý tín hiệu mặc định
Hệ thống đã dành sẵn các hàm mặc định xử lý tín hiệu cho mỗi tiến trình.
Bộ xử lý mặc định cho tín hiệu TERM gọi là hàm exit() - chấm dứt tiến trình hiện hành.
Bộ xử lý dành cho tín hiệu ABRT là gọi hàm hệ thống abort() để tạo ra file core lưu xuống thư mục hiện hành và thoát chương trình.
Mặc dù vậy, đối với một số tín hiệu, bạn có thể cài đặt hàm thay thế cho bộ xử lý tín hiệu mặc định của hệ thống Việc cài đặt bộ xử lý tín hiệu là cần thiết để tùy chỉnh cách hệ thống phản ứng với các tín hiệu cụ thể.
Có nhiều phương pháp để thiết lập bộ xử lý tín hiệu thay cho bộ xử lý tín hiệu mặc định Hai cách cơ bản nhất là sử dụng hàm signal() hoặc sigaction().
#include typedef void (*sighandler_t) (int); sighandler_t signal(int signum, sighandler_t handler);
Hàm signal() cho phép bạn thiết lập bộ xử lý cho một tín hiệu cụ thể được xác định bởi signum Bộ xử lý này có thể là SIG_IGN để bỏ qua tín hiệu, SIG_DFL để khôi phục cơ chế mặc định, hoặc một hàm do người dùng định nghĩa.
Ngoài ra Linux còn hỗ trợ một cách dùng signal mới hơn là sigaction:
#include int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Liên lạc giữa 2 tiến trình
Shared memory (bộ nhớ được chia sẻ) là cơ chế giao tiếp liên tiến trình
(IPC) có sẵn trong Linux và các hệ thống giống Unix khác, khi một bộ nhớ chung được sử dụng cho hai hoặc nhiều tiến trình khác nhau.
Trong các cơ chế giao tiếp giữa các tiến trình như pipe hay message queue, việc gửi dữ liệu giữa các tiến trình là cần thiết Tuy nhiên, với shared memory, các tiến trình có thể truy cập trực tiếp vào bộ nhớ chung mà không cần truyền dữ liệu Giao tiếp diễn ra thông qua bộ nhớ được chia sẻ, cho phép các thay đổi của một tiến trình có thể được nhìn thấy bởi các tiến trình khác.
Trong hình 5.1, quan hệ giữa tiến trình và bộ nhớ được chia sẻ cho thấy rằng các tiến trình có thể chia sẻ một vùng nhớ vật lý thông qua không gian địa chỉ của chúng Vùng nhớ chia sẻ này tồn tại độc lập với các tiến trình, và để truy cập vào vùng nhớ này, mỗi tiến trình cần phải kết gắn nó vào không gian địa chỉ riêng của mình, sau đó thực hiện các thao tác như trên vùng nhớ riêng Việc sử dụng bộ nhớ chia sẻ giúp tối ưu hóa hiệu suất và tăng cường khả năng giao tiếp giữa các tiến trình.
Linux cung cấp các hàm hệ thống được sử dụng để tạo và sử dụng shared memory như sau:
1 shmget () int shmget(key_t key, size_t size, int shmflg)
Các đối số quan trọng khi làm việc với bộ nhớ chia sẻ bao gồm: "key" là khóa nhận diện bộ nhớ, có thể là giá trị tùy ý hoặc được tạo từ hàm ftok() để đảm bảo tính duy nhất; "size" chỉ định kích thước của phân đoạn bộ nhớ chia sẻ; và "shmflg" xác định các cờ cần thiết như IPC_CREAT để tạo phân đoạn mới hoặc IPC_EXCL để đảm bảo rằng phân đoạn không tồn tại trước khi tạo Ngoài ra, cần lưu ý rằng đối số này cũng yêu cầu thiết lập quyền truy cập phù hợp cho việc sử dụng bộ nhớ chia sẻ.
Sau khi lệnh gọi sẽ hàm này được thực hiện thành công, shmget () trả về một mã định danh cho phân đoạn bộ nhớ được chia sẻ.
2 shmat () void * shmat(int shmid, const void *shmaddr, int shmflg)
Trong bài viết này, chúng ta sẽ khám phá các đối số quan trọng khi làm việc với bộ nhớ chia sẻ Đầu tiên, shmid là định danh của phân đoạn bộ nhớ chia sẻ, được trả về từ lệnh gọi hệ thống shmget() Tiếp theo, shmadrr chỉ định địa chỉ để gắn phân đoạn bộ nhớ, thường được đặt là NULL để hệ thống tự chọn địa chỉ phù hợp Cuối cùng, shmflg là cờ (flag) xác định các thuộc tính của bộ nhớ chia sẻ, bao gồm SHM_RND (làm tròn địa chỉ), SHM_EXEC (cho phép thực thi nội dung), SHM_RDONLY (đính kèm với mục đích chỉ đọc) và SHM_REMAP (thay thế ánh xạ hiện có trong phạm vi chỉ định).
Sau khi lệnh gọi hàm này được thực hiện thanh công, nó sẽ trả về địa chỉ mà phân đoạn bộ nhớ chia sẻ được gắn
3 shmdt () int shmdt(const void *shmaddr)
Sau khi hoàn thành tiến trình với bộ nhớ chia sẻ, bạn cần tách nó ra bằng cách sử dụng hàm hệ thống shmdt() Địa chỉ của phân đoạn bộ nhớ chia sẻ được tách ra sẽ được chỉ định qua tham số shmaddr.
4 shmctl () int shmctl(int shmid, int cmd, struct shmid_ds *buf)
Lệnh gọi hệ thống này cho phép điều khiển một phân đoạn bộ nhớ chia sẻ, trong đó shmid là ID định danh cho bộ nhớ chia sẻ và cmd là lệnh được sử dụng để thao tác trên bộ nhớ đó.
IPC_STAT là lệnh dùng để sao chép thông tin về các giá trị hiện tại của từng thành phần trong cấu trúc struct shmid_ds vào cấu trúc được chỉ định bởi con trỏ buf Lệnh này yêu cầu quyền đọc đối với phân đoạn bộ nhớ chia sẻ.
IPC_SET - Đặt ID người dùng, ID nhóm của chủ sở hữu, quyền, v.v. được trỏ đến theo cấu trúc buf.
IPC_RMID - Đánh dấu phân đoạn sẽ bị hủy Phân đoạn chỉ bị phá hủy sau khi tiến trình cuối cùng đã tách nó ra.
IPC_INFO - Trả về thông tin về giới hạn bộ nhớ dùng chung và các tham số trong cấu trúc được trỏ bởi buf.
Cấu trúc shm_info trong SHM_INFO cung cấp thông tin về tài nguyên hệ thống tiêu thụ bởi bộ nhớ chia sẻ Biến buf là con trỏ đến cấu trúc shmid_ds, và các giá trị trong cấu trúc này sẽ được sử dụng cho cả lệnh set và get theo cmd.
Tất cả các lệnh gọi hàm hệ thống sẽ trả về giá trị -1 nếu xảy ra lỗi Việc sử dụng shared memory mang lại nhiều ưu điểm, trong đó nổi bật là không cần truyền gửi dữ liệu, giúp tiết kiệm chi phí và là phương pháp nhanh nhất để trao đổi thông tin giữa các tiến trình.
Phương pháp này có nhược điểm là gây khó khăn trong việc đảm bảo sự toàn vẹn dữ liệu, đặc biệt là việc xác định dữ liệu mới nhất mà một tiến trình đang truy xuất.
Để ngăn chặn hai tiến trình ghi dữ liệu đồng thời vào vùng nhớ chung, cần áp dụng các cơ chế đồng bộ hóa thích hợp Tuy nhiên, việc sử dụng vùng nhớ chia sẻ không phải là giải pháp tối ưu cho các hệ thống phân tán khi cần trao đổi thông tin giữa các máy tính khác nhau.
Message queue hay hàng đợi tin nhắn cũng là một cơ chế IPC có sẵn trong
Trong hệ điều hành Linux, mỗi khối dữ liệu được truyền đi có một kiểu (TYPE) cụ thể, cho phép người nhận nhận dữ liệu theo đúng kiểu đó Cách tiếp cận này thường mang lại hiệu quả cao hơn so với việc nhận dữ liệu theo phương thức FIFO, như trong trường hợp sử dụng các pipe (đường ống).
Hình 5.2 Minh họa sử dụng message queue b Sử dụng message queue
Để hỗ trợ giao tiếp tiến trình qua message queue, hệ điều hành cung cấp các hàm IPC chuẩn, tương tự như với shared memory Những hàm này cho phép thực hiện giao tiếp giữa các tiến trình một cách hiệu quả.
1 msgget (): trả về ID định danh cho message queue mới được tạo hoặc trả về định danh của một message queue đã tồn tại cùng với một giá trị khóa nhận dạng của nó. int msgget(key_t key, int msgflg)
2 msgsnd (): Hàm hệ thống này được sử dụng để đưa dữ liệu vào message queue. int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
3 msgrcv (): Hàm hệ thống thống này giúp lấy dữ liệu ra khỏi môtj message queue. int msgrcv(int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflg)
4 msgctl (): Hàm hệ thống này cũng giúp thực hiện thao tác điều khiển một message queue. int msgctl(int msgid, int cmd, struct msqid_ds *buf) c Đánh giá việc sử dụng message queue
Lập lịch đa tiến trình
Lập lịch đa tiến trình bao gồm một tiến trình chính quản lý và giao việc cho các tiến trình con Tiến trình chính thực hiện nhiệm vụ đơn giản, không có lỗi, chủ yếu tập trung vào việc điều phối và phân bổ công việc cho các tiến trình con thay vì trực tiếp xử lý công việc.
Tạo ra tiến trình chính, tiến trình chính gọi các tiến trình con
Tiến trình con nhận nhiệm vụ (thường là nhận nhiệm vụ thông qua giao tiếp vs tiến trình chính), xử lý công việc liên tục
Tiến trình chính quản lý tiến trình con, xử lý khi tiến trình con chết, treo hoặc hoàn thành nhiệm vụ, như tạo mới hoặc dừng tiến trình Để liên lạc giữa các tiến trình, chúng ta sử dụng ống dẫn liên lạc (FIFO), là cơ chế cơ bản cho phép truyền thông gián tiếp qua các file đặc biệt Các ống dẫn không cung cấp truyền thông theo cấu trúc, với thao tác đọc độc lập khỏi thao tác ghi, khiến cho việc xác định kích cỡ và thông tin người gửi, người nhận trở nên khó khăn Tuy nhiên, ưu điểm của phương pháp này là cho phép sử dụng dữ liệu đã ghi nhiều lần để đọc chỉ một lần.
- Các ống dẫn chỉ mang tính chất tạm thời, chỉ tồn tại trong thời gian thực hiện của một tiến trình tạo ra nó.
Để tạo một ống dẫn, bạn cần bắt đầu bằng lệnh đặc biệt pipe() Hệ thống cung cấp hàm pipe() nhằm tạo ra đường ống với khả năng đọc và ghi.
Nhiều tiến trình có khả năng đọc và ghi dữ liệu trên cùng một ống dẫn, nhưng hiện tại không tồn tại cơ chế nào để phân biệt thông tin đầu ra cho các tiến trình khác nhau.
Dung lượng của ống dẫn dữ liệu chỉ khoảng 4KB, vì vậy khi chúng ta cố gắng ghi dữ liệu trong khi ống dẫn đã đầy, sẽ xảy ra tình trạng tắc nghẽn.
Các tiến trình liên lạc qua ống dẫn cần có mối quan hệ họ hàng, và các ống dẫn nối phải được mở trước khi tiến hành tạo ra các tiến trình con.
-Không thể tự thay đổi vị trí thông tin trong ống.
Tạo một ống dẫn: int p_desc[2]; int pipe(p_desc);
Giá trị trả về là 0 khi thành công và -1 khi thất bại p_desc[0] chứa các số hiệu mô tả để đọc trong ống dẫn, trong khi p_desc[1] chứa các số hiệu mô tả để viết trong ống dẫn.
Như vậy việc viết trong p_desc[1] là để truyền dữ liệu trong ống và việc đọc trong p_desc[0] để nhận chúng.
{ int i,ret, p_desc[2]; char c; pipe(p_desc); write(p_desc[1], "AB", 2); for (i=1; i