Tải bản đầy đủ (.doc) (30 trang)

Báo cáo bài tập lớn nguyên lý hệ điều hành

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (495.78 KB, 30 trang )


Bài tập lớn Nguyên lý hệ điều hành.

Mục Lục
..................................................................................................................................................1
Mục Lục.....................................................................................................................................2
1 Tổng quan về tiến trình Linux...................................................................................................5
1.1 Khái niệm.................................................................................................................................... 5
1.2 Phân loại tiến trình: .....................................................................................................................5
1.3 Các trạng thái của tiến trình..........................................................................................................8
1.4 Cấu trúc của một tiến trình...........................................................................................................8
1.5 Bảng thông tin tiến trình và xem thông tin tiến trình...................................................................10

2 Quản lý tiến trình...................................................................................................................11
2.1 Tạo lập tiến trình........................................................................................................................11
2.2 Dừng một tiến trình...................................................................................................................17
2.3 Cấp phát tài nguyên cho tiến trình..............................................................................................18
2.4 Giám sát và điều phối tiến trình..................................................................................................19
2.5 Kiểm soát và đợi tiến trình con...................................................................................................25
2.6 Liên lạc giữa các tiến trình..........................................................................................................27

3 Tổng Kết ................................................................................................................................29
4 Tài liệu tham khảo.................................................................................................................30

2


Bài tập lớn Nguyên lý hệ điều hành.

Lời nói đầu
Trước khi tìm hiểu về Linux, chúng ta cùng nói sơ qua về hệ điều hành UNIX- nền


tảng của Linux.
UNIX là hệ điều hành được Kenneth Thompson, Dennis Ritchie cùng một số người
khác phát triển vào năm 1969 tại phòng nghiên cứu Bell Labs trong công ty AT&T của Mỹ
với mục đích là tạo ra một môi trường làm việc đa người dùng khác với Windows của
Microsoft là hệ điều hành một người dùng. Phiên bản đầu tiên của UNIX ra đời năm 1971
với 60 câu lệnh bằng ngôn ngữ lập trình đơn giản. Từ đó trở đi, Hệ Điều Hành này phát
triển rất mạnh tuy nhiên nhược điểm của nó là chi phí rất đắt đỏ và cần có nhiều máy tính
cùng hoạt động. Điểm nhấn quan trọng giúp UNIX trở nệ phổ biến rông rãi là vào năm
1983, dự án GNU do Richard Stallman khởi xướng với mục tiêu tạo ra hệ thống các phần
mềm tương thích với UNIX và hoàn toàn miễn phí. Đến năm 1990, các phần mềm biên
dịch, các thư viện, các phần mềm xử lý văn bản, Unix shell và hệ thống quản lý cửa sổ đã
được tích hợp thành công mặc dù vẫn còn nhiều điểm yếu.
Linux kernel là nhân của một Hệ Điều Hành được viết dựa trên nền tảng của Hệ Điều
Hành UNIX do một sinh viên người Phần Lan có tên Linus Torvalds xây dựng. Linux ban
đầu có tên là Freax, sau đó, một người bạn của Linus đã đặt tên cho thư mục chứa kernel
trên FTP server do anh ta quản trị là Linux. Và tên của nó được phổ biến rộng khắp. Đến
nay, trên toàn thế giới đã có trên 10 triệu bản Linux được cài đặt với rất nhiều phiên bản và
các biến thể khác nhau. Ví dụ như Ubuntu, Fedora, Debian hay nổi tiếng nhất và được dùng
nhiều nhất hiện nay là Android- Hệ Điều Hành dùng trên các smartphone hiện đại. Linux
đang ngày càng được phổ biến trên toàn thế giới bởi những lí do:
Linux là hệ điều hành đa người dùng: hệ điều hành đa người dùng là hệ điều hành cho
phép nhiều người dùng cùng đăng nhập sử dụng và chạy các tiến trình trên hệ điều hành tại
cùng một thời điểm.
 Linux là hệ điều hành đa chức năng: ta có thể chạy nhiều ứng dụng tại cùng một
thời điểm. Hiện nay, tất cả các hệ điều hành đều làm được việc này, tuy nhiên, hiệu suất khi
chạy đồng thời các ứng dụng là không bằng nhau và đôi khi không ổn định.

3



Bài tập lớn Nguyên lý hệ điều hành.

 Linux là hệ điều hành ổn định: Linux là hệ điều hành có tính ổn định tuyệt vời
dựa trên cấu trúc của hệ điều hành và các modul tích hợp trên nó. Khi ta cài thêm phần
mềm mới hay thay đổi cấu hình của hệ thống thì bản không cần phải khởi động lại hệ
thống. Việc này giúp giảm thời gian và quản trị hệ thống dễ dàng hơn
 Linux là hệ điều hành với nhiều phần mềm có sẵn: Khi ta cài đặt thành công linux
ta sẽ có thể sử dụng ngay OpenOffice(tương đương với office của Microsoft), Gimp(giống
với photoshop) và rất nhiều phần mềm khác. Ngoài ra, ta cũng có thể download và cài đặt
miễn phí các phần mềm từ trang chủ.
 Linux hỗ trợ hầu hết các phần cứng của hệ thống: vì các driver đã được tích hợp
sẵn trong kernel nê khi cài đặt xong ta không phải cài thêm bất kỳ driver nào như khi cài hệ
điều hành Windows nữa.
 Linux là hệ điều hành chạy rất nhanh và sạch: Linux chạy rất nhanh và miễn dịch
với hầu hết các virus từ hệ điều hành Windows nên ta hoàn toàn có thể yên tâm khi sử
dụng.
Quản lý tiến trình là một trong những công việc hết sức quan trọng của bất kỳ hệ điều hành
nào. Nếu có cơ chế quản lý tốt thì hệ thống sẽ ổn định và mượt mà hơn. Sau đây, ta sẽ tìm hiểu kĩ
hơn về tiến trình và quản lý tiến trình trong hệ điều hành Linux.

4


Bài tập lớn Nguyên lý hệ điều hành.

1

Tổng quan về tiến trình Linux
1.1


Khái niệm

Tiến trình là một bộ phận của chương trình đang thực hiện, nó sở hữu một con trỏ
lệnh, tập các thanh ghi và các biến. Ngoài ra, tiến trình còn yêu cầu một số tài nguyên từ hệ
thống như CPU, bộ nhớ và các thiết bị.
Ngoài ra còn có nhiều khái niệm khác về tiến trình. Ở đây, chúng tôi xin giới thiệu
về hai định nghĩa tiến trình như sau:
+ Định nghĩa của Saltzer: Tiến trình là một chương trình do processor logic thực
hiện.
+ Định nghĩa của Horning & Rendell: Tiến trình là quá trình chuyển từ trạng thái
này qua trạng thái khác dưới tác động của hàm hành động từ một trạng thái ban đầu nào đó.
Ta cần phân biệt rõ hai khái niệm là chương trình và tiến trình. Chương trình là một
thực thể thụ động chứa đựng các chỉ thị điều khiển máy tính thực thi một tác vụ cụ thể nào
đó. Khi cho thực thi các tác vụ này, chương trình được chuyển thành các tiến trình- thực thể
hoạt động, với con trỏ lệnh xác định điạ chỉ kế tiếp sẽ thi hành kèm theo các tập tài nguyên
phục vụ cho hoạt động của tiến trình. Định nghĩa của Saltzer cho thấy trên góc độ thực thi
thì tiến trình hoàn toàn tương tự chương trình, chỉ khác ở chỗ: Tiến trình do processor logic
thực hiện mà không phải là processor vật lý. Định nghĩa của Horning & Rendell lại chỉ ra
rằng: Tiến trình thực hiện là sự chuyển đổi từ quá trình này sang quá trình khác nhưng sự
thay đổi này không phải do bản thân tiến trình mà do sự tác động bên ngoài, cụ thể ở đây là
bộ phận điều phối tiến trình của hệ điều hành. Những điều trên sẽ được thấy rõ trong quá
trình phân tích dưới đây.
1.2

Phân loại tiến trình:

Các tiến trình trong hệ thống có thể chia thành hai loại:
Tiến trình tuần tự và tiến trình song song. Tiến trình tuần tự là các tiến trình mà điểm
khởi tạo của nó là điểm kết thúc của tiến trình trước đó. Tiến trình song song là các tiến
5



Bài tập lớn Nguyên lý hệ điều hành.

trình mà điểm khởi tạo của tiến trình này mằn ở thân của các tiến trình khác, tức là có thể
khởi tạo một tiến trình mới khi các tiến trình trước đó chưa kết thúc. 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 song song nhưng

không có quan hệ thông tin với nhau, trong trường hợp này hệ điều hành phải thiết lập cơ
chế bảo vệ dữ liệu của các tiến trình, và cấp phát tài nguyên cho các tiến trình một cách hợp
lý.



Tiến trình song song có quan hệ thông tin: trong quá trình hoạt động các tiến

trình thường trao đổi thông tin với nhau, trong một số trường hợp tiến trình gửi thông báo
cần phải nhận được tín hiệu từ tiến trình nhận để tiếp tục, điều này dễ dẫn đến bế tắc khi
tiến trình nhận tín hiệu không ở trong trạng thái nhận hay tiến trình gửi không ở trong trạng
thái nhận thông báo trả lời.


Tiến trình song song phân cấp: Trong quá trình hoạt động một tiến trình có

thể khởi tạo các tiến trình khác hoạt động song song với nó, tiến trình khởi tạo được gọi là
tiến trình cha, tiến trình được tạo gọi là tiến trình con. Trong mô hình này hệ điều hành phải
giải quyết vấn đề cấp phát tài nguyên cho các tiến trình con. Tiến trình con nhận tài nguyên

ở đâu, từ tiến trình cha hay từ hệ thống. Để giải quyết vấn đề này hệ điều hành đưa ra 2 mô
hình quản lý tài nguyên: Thứ nhất, mô hình tập trung, trong mô hình này hệ điều hành chịu
trách nhiệm phân phối tài nguyên cho tất cả các tiến trình trong hệ thống. Thứ hai, mô hình
phân tán, trong mô hình này hệ điều hành cho phép tiến trình con nhận tài nguyên từ tiến
trình cha, tức là tiến trình khởi tạo có nhiệm vụ nhận tài nguyên từ hệ điều hành để cấp phát
cho các tiến trình mà nó tạo ra, và nó có nhiệm vụ thu hồi lại tài nguyên đã cấp phát trả về
cho hệ điều hành trước khi kết thúc.


Tiến trình song song đồng mức: là các tiến trình hoạt động song song sử dụng

chung tài nguyên theo nguyên tắc lần lượt, mỗi tiến trình sau một khoảng thời gian chiếm
giữ tài nguyên phải tự động trả lại tài nguyên cho tiến trình kia.
Các tiến trình tuần tự chỉ xuất hiện trong các hệ điều hành đơn nhiệm đa chương,
như hệ điều hành MS_DOS, loại tiến trình này tồn tại nhiều hạn chế, điển hình nhất là
6


Bài tập lớn Nguyên lý hệ điều hành.

không khai thác tối đa thời gian xử lý của processor. Các tiến trình song song xuất hiện
trong các hệ điều hành đa nhiệm đa chương, trên cả hệ thống uniprocessor và
multiprocessor. Nhưng sự song song thực, chỉ có ở các hệ thống multiprocessor, trong hệ
thống này mỗi processor chịu trách nhiệm thực hiện một tiến trình. Sự song song trên các
hệ thống uniprocessor là sự song song giả, các tiến trình song song trên hệ thống này thực
chất là các tiến trình thay nhau sử dụng processor, tiến trình này đang chạy thì có thể dừng
lại để nhường processor cho tiến trình khác chạy và sẽ tiếp tục lại sau đó khi có được
processor. Đây là trường hợp mà ở trên ta cho rằng: điểm khởi tạo của tiến trình này nằm
ở thân của tiến trình khác.
Hình vẽ sau đây minh họa sự khác nhau, về mặt thực hiện, giữa các tiến trình song

song/ đồng thời trong hệ thống uniprocessor với các tiến trình song song/ đồng thời trong
hệ thống multiprocessor.

P1
P2
P3

Time

a. Trong hệ thống uniprocessor
P1
P2
P3

Time

b. Trong hệ thống Multiprocessor
Hình 2.1: Sự thực hiện đồng thời của các tiến trình trong hệ
thống uniprocessor (a) và hệ thống multiprocessor (b).

Trong tài liệu này, chúng ta chỉ khảo sát sự hoạt động của các tiến trình song song
(hay đồng thời) trên các hệ thống uniprocessor.
Đối với người sử dụng thì trong hệ thống chỉ có hai nhóm tiến trình. Thứ nhất, là các
tiến trình của hệ điều hành. Thứ hai, là các tiến trình của chương trình người sử dụng. Các
7


Bài tập lớn Nguyên lý hệ điều hành.

tiến trình của hệ điều hành hoạt động trong chế độ đặc quyền, nhờ đó mà nó có thể truy

xuất vào các vùng dữ liệu được bảo vệ của hệ thống. Trong khi đó các tiến trình của
chương trình người sử dụng hoạt động trong chế độ không đặc quyền, nên nó không thể
truy xuất vào hệ thống, nhờ đó mà hệ điều hành được bảo vệ. Các tiến trình của chương
trình người sử dụng có thể truy xuất vào hệ thống thông qua các tiến trình của hệ điều hành
bằng cách thực hiện một lời gọi hệ thống.
1.3

Các trạng thái của tiến trình

Khi một chương trình đang chạy từ dòng lệnh, ta có thể nhấn tổ hợp phím ctrl+Z để
tạm dừng chương trình và đưa nó vào hoạt động phía hậu trường(background). Tiến trình
Linux có các trạng thái sau:
-Đang chạy(running): là trạng thái mà tiến trình chiếm quyền sử dụng CPU để tính
toán hay thực hiện các công việc của mình.
-Chờ(waiting): là trạng thái mà CPU tiến trình bị hệ điều hành tước quyền sử dụng
CPU, phải chờ cho đến lượt cấp phát khác.
-Tạm dừng(suspend): là trạng thái mà hệ điều hành tạm dừng tiến trình. Tiến trình
được đưa vào trang thái thái ngủ(sleep). Khi cần thiết và có nhu cầu hệ điều hành sẽ đánh
thức(wake up) hay nạp lại mã lệnh của tiến trình vào bộ nhớ, cấp phát tài nguyên CPU để
tiến trình tiếp tục hoạt động.
Trên dòng lệnh, thay vì dung lệnh ctrl+z, ta có thể dùng lệnh bg để đưa tiến trình vào
hoạt động phía hậu trường. Chúng ta có thể yêu cầu một chương trình chạy nền bằng cú
pháp &, chẳng hạn: $ls –R &. Lệnh fg sẽ đem tiến trình trở về hoạt động ưu tiên phía trước.
Thực tế khi chúng ta đăng nhập vào hệ thống và tương tác trên dong lệnh cũng là lúc ta
đang ở trong tiến trình shell của bash. Khi gọi một dòng lệnh có nghĩa là ta đã yêu cầu bash
tạo thêm một chương trình con thực thi khác. Về mặt lập trình,chúng ta có thể dùng lệnh
fork() để nhân bản một tiến trình khác từ tiến trình ban đầu, hoặc dùng lệnh system() để
triệu hồi một chương trình con từ hệ điều hành. Hàm exec() cũng có khả năng tạo ra một
tiến trình mới khác.
1.4


Cấu trúc của một tiến trình
8


Bài tập lớn Nguyên lý hệ điều hành.

Chúng ta cùng trả lời câu hỏi: Hệ Điều Hành quản lý tiến trình như thế nào?
Nếu có hai người dùng user1 và user2 cùng đăng nhập vào chạy chương trình chạy
grep đồng thời, thực tế hệ điều hành sẽ quản lý nạp mã của chương trình grep vào hai vùng
nhớ khác nhau và gọi mỗi phân vùng như vậy là tiến trình.
User1: chạy file grep tìm kiếm chuỗi abc trong file 1
$grep abc file1
User2: chạy file grep tìm kiếm chuỗi def trong file 2
$grep def file 2
Nếu dùng lệnh ps thì hệ thống sẽ liệt kê cho chúng ta thông tin của những tiến trình mà
hệ điều hành đang kiểm soát. Ví dụ: $ps –af
Mỗi tiến trình được gắn được gán cho một định danh để nhận dạng gọi là PID(process
identify). PID là số nguyên dương thường có giá trị từ 2 đến 32768. Khi một tiến trình mới
yêu cầu khởi động, hệ điều hành sẽ chọn lấy một số chưa bị tiến trình nào chiếm giữ trong
khoảng số nguyên trên và cấp phát cho tiến trình mới. Khi tiến trình kết thúc, hệ điều hành
sẽ thu hồi số PID để cấp phát cho tiến trình khác trong lần sau. PID được bắt đầu từ 2 vì 1
được dành cho tiến trình đầu tiên gọi là init. Tiến trình init được nạp và chạy ngay khi
chúng ta khởi động hệ điều hành. Init là tiến trình quản lý và tạo ra mọi tiến trình con khác.
Ở ví dụ trên chúng ta thấy lệnh $ps –af sẽ hiển thị hai tiến trình grep chạy bởi user 1 và
user2 với số PID lần lượt là 101 và 102.
Mã lệnh thực thi của lệnh grep được chứa trong tập tin trên đĩa cứng được hệ điều hành
nạp vào vùng nhớ. Mỗi tiến trình được hệ điều hành phân chia rõ ràng: vùng chứa mã lệnh
(code) và vùng chứa dữ liệu (data). Mã lệnh thường giống nhau và có thể sử dụng chung.
Linux quản lý cho phép tiến trình của cùng một chương trình có thể dùng chung mã lệnh

của nhau. Thư viện cũng vậy, trừ những thư viện đặc thù, các thư viện chuẩn sẽ được hệ
điều hành cho phép chia sẻ và dùng chung bởi các chương trình trong hệ thống. Bằng việc
sử dụng chung thư viện, kích thước các chương trình giảm đi đáng kể. Mã lệnh của chương
trình khi chạy trong hệ thống ở dạng tiến trình cũng đỡ tốn bộ nhớ hơn.
Trừ mã lệnh và thư viện có thể chia sẻ, dữ liệu thì không. Mỗi phân đoạn sở hữu một

9


Bài tập lớn Nguyên lý hệ điều hành.

phân đoạn dữ liệu riêng. Ví dụ tiến trình grep do user1 nắm giữ lưu trữ biến s có giá trị
‘abc’ còn tiến trình grep do user2 nắm giữ lưu trữ biến s có giá trị ‘def’.
Mỗi tiến trình cũng được hệ thống dành riêng cho một bảng mô tả file(file description
table). Bảng này chứa các số mô tả áp đặt cho các file đang được mở. Mỗi tiến trình khi
khởi động, Hệ Điều Hành sẽ mở cho chúng ta 3 file: stdin(số mô tả 0), stdout(số mô tả 1)
và stderr(số mô tả 2). Các file này tượng trưng cho các thiết bị nhập, xuất và thông báo lỗi.
chúng ta có thể mở thêm các file khác. Ví dụ user1 mở file1, user2 mở file2. Hệ Điều Hành
cáp phát số mô tả file cho các tiến trình và lưu riêng chúng trong bảng mô tả file của tiến
trình đó.
Ngoài ra mỗi tiến trình có riêng ngăn xếp stack để lưu trữ biến cục bộ và giá trị trả về
sau lời gọi hàm. Tiến trình cũng được giành cho khoảng không gian riêng để lưu trữ các
biến môi trường. Chúng ta sẽ dùng lệnh putenv và getenv để đặt riêng biến môi trường cho
từng tiến trình.
1.5

Bảng thông tin tiến trình và xem thông tin tiến trình

Hệ điều hành lưu trữ một cấu trúc danh sách bên trong hệ thống gọi là bảng tiến
trình(process table). Bảng tiến trình quản lý tất cả các PID và thông tin chi tiết về các tiến

trình đang chạy. Ví dụ như khi ta gọi lệnh ps, Linux thường đọc thông tin trong bảng tiến
trình này và hiển thị tên và các lệnh của các tiến trình được gọi: thời gian sử dụng CPU của
tiến trình, tên người sử dụng tiến trình,…
Lệnh ps của hệ điều hành dùng để xem thông tin của các tiến trình. Tùy theo tham số
lệnh ps sẽ cho ta thông tin về tiến trình người dùng, tiến trình của hệ thống hoặc tất cả các
tiến trình đang chạy. Ví dụ ps sẽ đưa ra chi tiết bằng tham số -af.
Trong thông tin do ps trả về, UID là tên người dùng đã gọi tiến trình, PID là số định
danh mà hệ thống cấp cho tiến trình, PPID là số định danh của tiến trình cha(parent PID). Ở
đây chúng ta sẽ gặp một số tiến trình có định danh PPID là 1, là định danh của tiến trình
init, được gọi và chạy khi khởi động. Nếu ta hủy tiến trình init thì hệ điều hành sẽ chấm dứt
phiên làm việc. STIME là thời điểm tiến trình được đưa vào sử dụng. TIME là thời gian
chiếm dụng CPU của tiến trình, CMD là toàn bộ dòng lệnh khi tiến trình được triệu gọi,
10


Bài tập lớn Nguyên lý hệ điều hành.

TTY là màn hình terminal ảo nơi gọi thực thi tiến trình. Như chúng ta đã biết người dùng
có thể đăng nhập từ rất nhiều terminal khác nhau để gọi tiến trình. Để liệt kê các tiến trình
hệ thống ta sử dụng lệnh $ps –ax.

2

Quản lý tiến trình
Hệ điều hành các thao tác chủ yếu sau đây cho một tiến trình:
+ tạo lập tiến trình(create)

+ tạm dừng một tiến trình(suspend)

+ dừng một tiến trình(destroy)


+ tái kích hoạt tiến trình(resume)

+ thay đổi độ ưu tiên đối với tiến trình

+cấp phát tài nguyên cho tiến trình

+ giám sát và điều phối

+kiểm soát và đợi tiến trình con

Sau đây chúng ta sẽ cùng tìm hiểu lần lượt về các thao tác nói trên:
2.1

Tạo lập tiến trình

Hình 1: Một cây tiến trình trong hệ thống Linux
Để tạo lập tiến trình, hệ điều hành cần làm các công việc sau:
+ định danh cho tiến trình mới phát sinh
11


Bài tập lớn Nguyên lý hệ điều hành.

+ đưa tiến trình này vào danh sách quản lý của hệ thốn
+ xác định độ ưu tiên của tiến trình vừa tạo
+ lập bảng PCB cho tiến trình
+ cấp phát tài nguyên ban đầu cho tiến trình
 Tạo lập tiến trình bằng hàm system()
Chúng ta có thể gọi tiến trình khác bên trong một tiến trình đang thực thi bằng hàm

system(). Có nghĩa là chúng ta có thể tạo ra một tiến trình mới từ tiến trình đang chạy. Hàm
system() được khai báo như sau:
#include <stdlib.h>
int system( const char (cmdstr) )
Hàm này gọi chuỗi lệnh cmdstr thực thi và chờ lệnh chấm dứt mới quay về nơi gọi hàm
tương đương với việc gọi hàm shell thực thi lệnh hệ thống: $sh –c cmdstr
System() sẽ trả về mã lỗi 127 nếu không khởi động được shell để thực hiện lệnh cmdstr.
Mã lỗi là 1 nếu gặp các lỗi khác. Còn lại mã trả về của system() là mã lỗi do cmdstr sau khi
lệnh được gọi trả về.
Ví dụ sử dụng hàm system(), system.c
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf( "Thuc thi lenh ps voi system\n" );
system( "ps –ax" );
printf( "Thuc hien xong. \n" );
exit( 0 );
}
Hàm system() của chúng ta được sử dụng để gọi lệnh ‘ps –ax’.
12


Bài tập lớn Nguyên lý hệ điều hành.

 Thay thế tiến trình hiện hành với hàm exec()
Mỗi tiến tình được hệ điều hành cấp cho một không gian nhớ để các tiến trình tự do
hoạt động. Nếu tiến trình A của chúng ta gọi một tiến trình ngoài B thì hệ điều hành thường
thực hiện các thao tác như: cấp phát không gian nhớ cho tiến trình mới, điều chỉnh lại danh
sách các tiến trình, nạp mã lệnh của chương trình B trên đĩa cứng vào không gian nhớ vừa

cấp phát cho tiến trình, đưa tiến trình mới vào danh sách các tiến trình cần điều phối của hệ
điều hành. Những công việc này thường mất thời gian đáng kể và chiếm dụng thêm tài
nguyên của hệ thống.
Nếu tiến trình A đang chạy và nếu ta muốn tiến trình B khởi động và chạy trong không
gian nhớ có sẵn của tiến trình A, ta có thế dùng hàm exec() được cung cấp bởi Linux. Các
hàm exec() sẽ thay thế hoàn toàn ảnh của tiến trình A(tập lệnh, dữ liệu, bảng mô tả file)
thành ảnh của tiến trình B hoàn toàn khác. Chỉ có chỉ số định danh PID của tiến trình A
được giữ lại. Tập hàm exec() bao gồm các hàm sau:
#include <unistd.h>
extern 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 *const envp[] );
int exect( const char *path, char *const argv[] );
int execv( const char *path, char *const argv[] );
int execvp( const char *file, char *const argv[] );
Đa số các hàm này đều yêu cầu chúng ta chỉ đối số path hoặc file là đường dẫn đến tên
chương trình cần được thực thi trên đĩa. Arg là đối số cần truyền cho chương trình cần thực
thi, những đối số này tương tự cách chúng ta gọi chương trình từ dòng lệnh.
Ví dụ về việc sử dụng hàm exec và pexec.c
#include <unistd.h>
13


Bài tập lớn Nguyên lý hệ điều hành.

#include <stdio.h>
int main()
{
printf( "Thuc thi lenh ps voi execlp\n" );

execlp( "ps", "ps", "–ax", 0 );
printf( "Thuc hien xong. Nhung chung ta se khong thay duoc dong nay.\n" )
exit( 0 );
}
 Nhân bản tiến trình với hàm fork()
Thay thế tiến trình đôi khi bất lợi với chúng ta. Đó là tiến trình mới chiến giữ toàn bộ
không gian nhớ của tiến trình cũ và chúng ta không thể kiểm soát cũng như điều khiển tiếp
tiến trình hiện hành của mình sau khi gọi hàm exec() nữa. Cách đơn giản mà các chương
trình của Linux thường dùng là hàm fork() để nhân bản hay tạo một bản mới của tiến trình.
Fork() là một hàm khá đặc biệt, khi thực thi, nó sẽ trả về hai giá trị khác nhau trong khi
bình thường một hàm chỉ trả về một giá trị trong một lần thực thi. Khai báo của hàm fork()
như sau:
#include <sys/types.h>
#include <unistd.h>
pid_t fork()
Nếu thành công fork() sẽ tách tiến trình hiện hành thành hai tiến trình(dĩ nhiên hệ điều
hành phải cấp phát thêm không gian nhớ cho tiến trình mới). Tiến trình ban đầu gọi là tiến
trình cha(parent process) và tiến trình mới gọi là tiến trình mới gọi là tiến trình con(child
process), tiến trình con sẽ có một số định danh PID riêng biệt. ngoài ra tiến trình con còn
mang thêm một số định danh PPID là số định danh của tiến trình cha.

14


Bài tập lớn Nguyên lý hệ điều hành.

Sau khi tách tiến trình thì mã lệnh ở hai tiến trình được sao chép là giống hệt nhau. Chỉ
có một dấu hiệu để ta nhận dạng được tiến trình cha và con là giá trị trả về của hàm fork().
Bên trong tiến trình con, hàm fork() sẽ trả về giá trị 0. Trong khi bên trong tiến trình cha thì
giá trị trả về là trị số nguyên chỉ là số PID của tiến trình con vừa tạo. Nếu không tách được

tiến trình thì hàm fork() sẽ trả về giá trị -1. Kiểu pid_t được khai báo và định nghĩa trong
uinstd.h là kểu số nguyên(int).
Đoạn mã điều khiển và sử dụng hàm fork() thường có dạng chuẩn sau:
pid_t new_pid;
new_pid = fork(); // tách tiến trình
switch (new_pid)
{
case -1: printf( "Khong the tao tien trinh moi" ); break;
case 0: printf( "Day la tien trinh con" );
// mã lệnh dành cho tiến trình con đặt ở đây
break;
default: printf( "Day la tien trinh cha" );
// mã lệnh dành cho tiến trình cha đặt ở đây
break;
}
Ví dụ sử dụng hàm fork(), fork_demo.c
#include <sys/types.h>
#include <unistd.h>

#include <stdio.h>
int main()
{
15


Bài tập lớn Nguyên lý hệ điều hành.

pid_t pid;
char * message;
int n;

printf( "Bat dau.\n" );
pid = fork();
switch ( pid )
{
case -1: printf( "Khong the tao tien trinh moi" ); exit(1);
case 0: message = "Day la tien trinh con";
n = 0;
for ( ; n < 5; n++ )
{
printf( "%s", message );
sleep( 1 );
}
break;
default: message = "Day la tien trinh cha";
n = 0;
for ( ; n < 3; n++ )
{
printf( "%s", message );
sleep( 1 );
break;
}
Exit(0);
16


Bài tập lớn Nguyên lý hệ điều hành.

}
Biên dịch và thực thi chương trình này ta thấy rằng cả hai tiến trình thực hiện đồng thời
và in ra kết quả đan xen nhau. Nếu muốn xem sự liên quan giữa PID và PPID của hai tiến

trình cha và con thì tha có thể sử dụng dòng lệnh sau:
$fork_demo & ps – af
2.2

Dừng một tiến trình

Trong nhiều trường hợp, một tiến trình có thể bị treo, một chương trình server cần nhận cấu
hình mới, card mạng cần thay đổi địa chỉ IP …, khi đó chúng ta phải dừng tiến trình đang
có vấn đề. Ulinux có lệnh kill để thực hiện các công tác này. Trước tiên ta cần phải biết
PID của tiến trình cần dừng thông qua lệnh ps. Chỉ có super-user mới có quyền dừng tất cả
các tiến trình, còn người sử dụng chỉ được dừng các tiến trình của mình.
 Lệnh kill
Kill -9 PID_của_tiến_trình
Tham số –9 là gửi tín hiệu dừng không điều kiện chương trình. Chú ý nếu ta logged in
vào hệ thống như root, nhập số PID chính xác nếu không ta có thể dừng một tiến trình
khác. Không nên dừng các tiến trình mà mình không biết vì có thể làm treo máy hoặc dịch
vụ.
Một tiến trình có thể sinh ra các tiến trình con trong quá trình hoạt động của mình. Nếu ta
dừng tiến trình cha, các tiến trình con cũng sẽ dừng theo, nhưng không tức thì. Vì vậy phải
đợi một khoảng thời gian và sau đó kiểm tra lại xem tất cả các tiến trình con có dừng đúng
hay không. Trong một số hãn hữu các trường hợp, tiến trình có lỗi nặng không dừng được,
phương pháp cuối cùng là khởi động lại máy.
Khi kết thúc một tiến trình, hệ điều hành cần làm các công việc sau:
+ thu hồi tài nguyên hệ thống đã cấp phát cho tiến trình
+ hủy tiên trình khỏi tất cả các danh sách quản lý của hệ thống
+ hủy bỏ PCB của tiến trình

17



Bài tập lớn Nguyên lý hệ điều hành.

Hầu hết các hệ điều hành không cho phép tiếp tục chương trình con khi chương trình
cha đã kết thúc. Nếu hiện tượng này xảy ra, hệ diều hành sẽ thực hiện một loạt thao tác để
kết thúc chương trình con.
2.3

Cấp phát tài nguyên cho tiến trình

Khi có nhiều người cùng làm việc trên hệ thống, hệ điều hành phải cấp phát tài nguyên
yêu cầu cho mỗi người sử dụng. Do tài nguyên hệ thống thường rất giới hạn và nhiều khi
không thể chia sẻ nên hiếm khi đồng thời các yêu cầu tài nguyên đề được thỏa mãn. Vì thế
phải nghiên cứu ra phương pháp chia sẻ một số tài nguyên hữu hạn giữa nhiều tiến trình
người dùng đồng thời. Hệ điều hành quản lý nhiều loại tài nguyên khác nhau như: CPU, bộ
nhớ chính, các thiết bị ngoại vi, vv…Với mỗi loại tài nguyên cần có cơ chế và các chiến
lược cấp phát hiệu quả. Mỗi tài nguyên được biểu diễn thông qua một cấu trúc dữ liệu,
khác nhau về chi tiết cho mỗi loại tài nguyên, nhưng về cơ bản bao gồm những thông tin
sau:
+ định danh tài nguyên
+ trạng thái tài nguyên: phần nào của tài nguyên đã được sử dụng, phần nào còn có
khả năng cấp phát?
+ hàng đợi trên một tài nguyên: các tiến trình đang chờ cấp phát tài nguyên tương
ứng
+ bộ cấp phát: là đoạn code đảm nhiệm việc cấp phát một tài nguyên đặc thù. Một số
tài nguyên đòi hỏi các giải thuật đặc biệt, ví dụ như CPU, bộ nhớ trong hay hệ thống các
tập tin. Trong khi một số khác lại có giải thuật cấp phát và giải phóng tổng quát hơn, ví dụ
như: các thiết bị ngoại vi

18



Bài tập lớn Nguyên lý hệ điều hành.

Hình 2:Khối quản lý tài nguyên
Kĩ thuật cấp phát phải:
+đảm bảo một số lượng hợp lệ các tiến trình truy xuát đến các tài nguyên không thể
chia sẻ
+ cấp phát tài nguyên cho tiến trình có yêu cầu trong trong thời gian trì hoãn có thể
chấp nhận được
+ tối ưu hóa việc sử dụng tài nguyên
Để giải quyết tốt các yêu cầu trên, ta cần giải quyết vấn đề nảy sinh khi có nhiều tiến
trình yêu cầu đồng thời một tài nguyên không thế chia sẻ.
2.4

Giám sát và điều phối tiến trình

Mục tiêu của việc điều phối tiến trình là:
+ sự công bằng: không có tiến trình nào phải chờ đợi vô hạn
+ tình hiệu quả: hệ thống phải tận dụng CPU 100% thời gian

19


Bài tập lớn Nguyên lý hệ điều hành.

+ thời gian đáp ứng hợp lý: cố gắng cực tiểu hóa thời gian đáp ứng những yêu cầu
của người sử dụng
+ thời gian lưu lại trong hệ thống: cực tiểu hóa thời gian hoàn tất các tác vụ xử lý
theo lô
+ thời lượng tối đa: cực đại hóa số lượng các công việc xử lý được trong một đơn vị

thời gian
Tuy nhiên không thể đáp ứng toàn bộ các mục tiêu trên mà ta chỉ có thể dung hòa chúng
ở một mức độ nào đó.
Một chương trình là một file thực thi trong hệ thống, ví dụ như : /sbin/shutdown hay
/sbin/init .
Tiến trình là một trường hợp của chương trình được thực thi. Ví dụ như khi ta mở cùng
lúc nhiều cửa sổ word, khi đó mỗi của sổ là một trường hợp của word.
Tiến trình đôi khi còn đc gọi là task.
Ta có thể lấy thông tin của tiến trình bằng lên ps, pstree, top
Ví dụ với lệnh ps :
#ps <option>
Option:
f: thể hiện các process dưới dạng tree
l: thể hiện dưới dạng long list
w: thể hiện dưới dạng wide output
x: Xem cả các process không gắn với terminal (daemon)
a: process của các user khác
U: user xem process của một user cụ thể
u: thể hiện dưới dạng “user format”

20


Bài tập lớn Nguyên lý hệ điều hành.

Ta có bảng thể hiện các trường trong bảng trên:

21



Bài tập lớn Nguyên lý hệ điều hành.

Với lệnh pstree tương tự lệnh ps với tham số -f, tham số -p in ra màn hình cả PID:

22


Bài tập lớn Nguyên lý hệ điều hành.

Lệnh Top giống lệnh ps nhưng danh sách process được update liên tục. Các thông số về
CPU và RAM cũng được thể hiện và update.

23


Bài tập lớn Nguyên lý hệ điều hành.

Ngoài ra, còn một số thao tác với tiến trình như sau:
 Gửi tín hiệu cho một tiến trình đang chạy với lệnh: # kill <signal | number>

 Thay đổi thông số priority với lệnh nice và renice.

+ nice dùng để thay đổi nice number của tiến trình tại thời điểm bắt đầu
# nice [–n number] [command]
+renice dùng để thay đổi nice number của các tiến trình đã chạy
# renice priority PID [[-g] group] [[-u] user]
 Can thiệp vào hoạt động của tiến trình

 Ngưng và tạm ngưng Job


+ Để thực hiện ngưng Job đang thực thi ta dùng tổ hợp phím ctrl+C. Sau đó ta có thể dùng
lệnh Jobs để hiển thị trạng thái của tiến trình đang chạy.
+ Để thực hiện tạm ngưng Job, ta dùng tổ hợp phím ctrl+Z, sau đó thì có thể thực hiện một
trong hai lệnh sau:
 bg: tiếp tục job vừa ngừng ở trạng thái background
24


Bài tập lớn Nguyên lý hệ điều hành.

2.5

Kiểm soát và đợi tiến trình con

Khi fork() tách tiến trình thành hai tiến trình cha và con, trên thực tế cả 2 đều hoạt động
độc lập. Đôi lúc tiến trình cha cần phải đợi tiến trình con thực hiện xong các tác vụ thì mới
tiếp tục thực thi. Ở ví dụ trên, khi thực thi ta thấy rằng khi tiến trình cha kết thúc thì tiến
trình con vẫn tiếp tục in ra thông báo và cả tiến trình con và cha đều đồng thời gửi thông
báo ra màn hình. Chúng ta không muốn thấy điều này, chúng ta muốn khi tiến trình cha kết
thúc thì tiến trình con cũng hoàn tất thao tác của nó. Hơn nữa chương trình con cần thực
hiện xong các thao tác của nó thì mới đến chương trình cha. Để làm được việc này chúng
ta sử dụng hàm wait():
#include<sys/types.h>
#include<sys/wait.h>
Pid_t wait(int &stat_loc)
Hàm wait() khi được gọi thì sẽ yêu cầu tiến trình cha dừng lại chờ tiến trình con kết
thúc trước khi thực hiện tiếp các lệnh điều khiển trong tiến trình cha. Wait() làm cho sự liên
hệ giữa tiến trình cha và tiến trình con trở nên tuần tự. Khi tiến trình con kết thúc hàm sẽ trả
về số PID tương ứng của tiến trình con. Nếu chúng ta truyền thêm đối số stat_loc khác
NULL cho hàm thì wait() cũng sẽ trả về trạng thái kết thúc của tiến trình con trong biến

stat_loc. Chúng ta có thể sử dụng các macro khai báo sẵn trong sys/wait.h như sau:
WIFEXITED (stat_loc) Trả về trị khác 0 nếu tiến trình con kết thúc bình thường.
WEXITSTATUS (stat_loc) Nếu WIFEXITED trả về trị khác 0, macro này sẽ trả về mã lỗi
của tiến trình con.
WIFSIGNALED (stat_loc) Trả về trị khác 0 nếu tiến trình con kết thúc bởi một tín hiệu
gửi đến.
WTERMSIG(stat_loc) Nếu WIFSIGNALED khác 0, macro này sẽ cho biết số tín hiệu đã
hủy tiến trình con.
WIFSTOPPED(stat_loc) Trả về trị khác 0 nếu tiến trình con đã dừng.
25


×