Tải bản đầy đủ (.ppt) (56 trang)

Chương 7: Xử lý tiến trình trong Linux

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 (687.7 KB, 56 trang )

1
Chương 7:
Chương 7:
Xử lý tiến trình trong Linux
Xử lý tiến trình trong Linux
CITD - VNUHCM
Bao g m các ph n sau:ồ ầ
1. Khái quát v ti n trình trong Linuxề ế
2. Cách ho t đ ng c a ti n trìnhạ ộ ủ ế
3. C u trúc ti n trìnhấ ế
4. T o l p ti n trìnhạ ậ ế
5. Đ c thông tin v các ti n trìnhọ ề ế
2
7.1. Khái quát về tiến trình trong Linux
7.1. Khái quát về tiến trình trong Linux
-
Mục tiêu: Nắm vững cơ chế hoạt động của các HĐH đa
nhiệm thông qua khái niệm tiến trình (Process)
-
Điểm nổi bật của các HĐH tựa Unix là khả năng chạy đồng
thời nhiều chương trình (Multi-Programming).
-
HĐH xem mỗi đơn thể mã lệnh mà nó điều khiển là Tiến
trình.
-
Một ứng dụng có thể bao gồm nhiều tiến trình kết hợp với
nhau.
3
- Các tiến trình cùng hoạt động  chia sẻ thời gian
CPU, có thể dùng chung vùng nhớ và các tài nguyên
hệ thống khác.


-
Các lệnh của Linux thực tế là những tiến trình riêng
lẻ, có khả năng kết hợp và truyền dữ liệu cho nhau
thông qua cơ chế giao tiếp liên tiến trình IPC (Inter-
Process Communications)
-
Chúng ta sẽ biết cách tạo, hủy, tạm dừng tiến trình
trong Linux. Đồng thời, tìm hiểu sâu cơ chế đồng bộ
hóa và giao tiếp giữa các tiến trình.
4
- Không như môi trường đơn nhiệm chỉ có một tiến
trình hoạt động, môi trường đa nhiệm có tài nguyên rất
hạn hẹp.
-
Khi hệ thống yêu cầu, tiến trình phải trong trạng thái
sẵn sàng nhường quyền xử lý CPU cho các tiến trình
khác ở bất kỳ thời điểm nào.
-
Tiến trình được định nghĩa: Là một thực thể điều
khiển đoạn mã lệnh có riêng một không gian địa chỉ,
có ngăn xếp riêng, có bảng chứa các mô tả tập tin
đang mở và đặc biệt là có một định danh PID
(Process Identifier) duy nhất trong toàn bộ hệ thống
vào thời điểm tiến trình đang chạy.
5
- Nhiều tiến trình có thể thực thi trên cùng một máy
với cùng một HĐH, cùng một người dùng (hoặc nhiều
người dùng đăng nhập khác nhau). Ví dụ: Shell Bash
là một tiến trình có thể thực thi lệnh ls hay cp (trong
khi bản thân hai lệnh trên là những tiến trình có thể

hoạt động tách biệt khác)
-
Hai tiến trình khác nhau không thể xâm phạm vùng
nhớ của nhau  Tuy nhiên, để chia sẻ dữ liệu giữa hai
tiến trình có thể sử dụng vùng không gian địa chỉ
chung.
6
7.2. Cách hoạt động của tiến trình
7.2. Cách hoạt động của tiến trình
-
Trong môi trường HĐH Linux, một tiến trình có các trạng thái sau:
Running (Đang chạy): Tiến trình chiếm quyền xử lý CPU
Waiting (Chờ): Tiến trình bị HĐH “tước” quyền xử lý CPU
Suspend (Tạm dừng): HĐH tạm dừng tiến trình  Sleeping
-
Tại dòng lệnh, có thể bấm Ctrl-Z để tạm ngừng tiến trình sau đó dùng
lệnh bg để đưa nó vào hậu trường để sau đó dùng fg chuyển lên mặt
trước.
-
Hàm fork() để nhân bản một tiến trình.
-
Hàm system() để tạo lập tiến trình mới.
-
Hàm exec() dùng thay thế tiến trình hiện hành.
7
7.3. Cấu trúc tiến trình
7.3. Cấu trúc tiến trình
-
Cách thức quản lý tiến trình của Linux:
 Hai user neil và rick cùng đăng nhập và chạy chương trình grep

đồng thời  HĐH lúc này sẽ quản lý và nạp mã truy cập chương
trình grep vào hai vùng nhớ khác nhau và gọi mỗi phân vùng như là
một tiến trình.

Hình 7.1 người dùng neil chạy
chương trình grep tìm chuỗi “abc”
trong tập tin treck.txt còn người
dùng rick chạy chương trình grep
tìm chuỗi “cde” trong tập tin
somefile.doc
Hình 7.1
Tiến trình quản lý bởi HĐH
neil
$grep abc treck.txt
PID 101
Code
Data
S=abc
Library
filedes
Mã lệnh
grep
Thư viện C
rick
$grep cde somefile.doc
PID 102
Code
Data
S=cde
Library

filedes
treck.txt somefile.doc
Không gian của Hệ điều hành
8
-
Dùng lệnh ps cho phép xem thông tin về các tiến trình mà Linux đang
kiểm soát (có thể sử dụng thêm tham số “-af” để liệt kê chi tiết thông tin
về các tiến trình):
Hình 7.1.a
Liệt kê thông tin về các tiến trình trên hệ thống
9
-
Mỗi tiến trình được gán cho một định danh gọi là PID (Process
Identifier)
-
PID là một số nguyên dương có giá trị từ 2 – 32768
-
Tiến trình init được gọi và chạy ngay khi ta khởi động HĐH. Đây là
tiến trình quản lý và tạo ra mọi tiến trình con khác  Có PID là 1
-
Cách thức gán PID: Khi một tiến trình mới yêu cầu khởi động, HĐH sẽ
chọn lấy một giá trị số nguyên trong khoảng 2 – 32768 (số nguyên này
chưa bị tiến trình đang chạy nào chiếm giữ) và cấp phát cho tiến trình
này. Khi tiến trình chấm dứt, HĐH sẽ thu lại số PID để cấp phát cho tiến
trình khác trong lần sau.
-
Trên Unix/Linux, thư mục /proc chứa các file lưu trữ thông tin về
những tiến trình đang chạy.
-
Theo quy ước, mỗi tiến trình hoạt động trong không gian địa chỉ ảo độc

lập do hệ thống cấp phát  4GB (có liên quan đến phân vùng SWAP đã
được đề cập ở Chương 1)
10
7.3.1. Bảng thông tin tiến trình
-
HĐH 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 của hệ thống cùng với thông tin
chi tiết về các tiến trình đang chạy.
-
Bảng tiến trình tựa như bảng của CSDL lưu các record là thông tin về
tiến trình. Trong đó, số PID thường được sử dụng làm khóa chính và
đánh chỉ mục để truy xuất thông tin.
-
Trong các phiên bản Unix/Linux cũ, giới hạn không được có hơn 256
tiến trình chạy đồng thời. Tuy nhiên, trên các hệ Unix/Linux có phiên
bản mới hiện nay  số tiến trình là không giới hạn chỉ phụ thuộc vào
bộ nhớ sẵn có.
11
7.3.2. Xem thông tin của tiến trình
-
Sử dụng lệnh ps để hiển thị thông tin chi tiết về các tiến trình (Xem lại
Hình 7.1.a)
-
Lệnh trên liệt kê nhiều tiến trình, kể cả những tiến trình chạy ở chế độ
đồ họa X-Window.
-
Các thông tin về kết xuất của lệnh ps như sau:
• UID: Tên người dùng đã gọi tiến trình

• PID: Số định danh mà hệ thống cung cấp cho tiến trình
• PPID: Số định danh của tiến trình cha (init có PID là 1)
• STIME: Thời điểm bắt đầu đưa tiến trình vào chạy
• TIME: Khoảng thời gian chiếm dụng CPU của tiến trình
• CMD: Toàn bộ dòng lệnh triệu gọi tiến trình
• TTY: Chỉ ra màn hình Terminal ảo nơi gọi thực thi tiến trình
12
7.3.3. Các tiến trình hệ thống
-
Sử dụng lệnh ps với tham số là “-ax” để xem các tiến trình của hệ thống
-
Xét tiến trình ở dòng đầu: Các tiến trình hệ thống (ở đây là init) không
gắn với terminal nào hết nên ở cột TTY của tiến trình init  sẽ có giá trị
là “?”
-
Tiến trình cuối cùng khi mà init gọi trước khi chuyển giao quyền điều
khiển cho Shell đó là tiến trình getty (Trình yêu cầu nhập username /
password lúc đăng nhập).
13
7.3.4. Điều phối tiến trình
-
Các HĐH đa nhiệm, đa tiến trình như Unix/Linux
(hay cả MS Windows NT/2000/XP/2003,…) điều có
trách nhiệm điều phối sự hoạt động đồng bộ của các
tiến trình.
-
Bộ điều phối tiến trình (Process Scheduler) của
HĐH liên tục xoay vòng và cung cấp một thời gian đủ
để các tiến trình thực hiện một phần công việc của nó.
Thông thường, khoảng thời gian cho phép tiến trình

chiếm giữ CPU là rất nhỏ.
14
- Không một tiến trình nào “độc chiếm” toàn bộ CPU suốt
thời gian dài gây ảnh hưởng đến các tiến trình khác.
-
Mỗi tiến trình có thể được cấp một độ ưu tiên (Priority)
nhất định.
-
Độ ưu tiên của tiến trình có thể điều chỉnh được bằng
lệnh renice
15
7.4. Tạo lập tiến trình
7.4. Tạo lập tiến trình
7.4.1. Gọi tiến trình mới bằng hàm system()
-
Gọi một chương trình khác bên trong một chương trình đang thực thi
bằng hàm system()
#include <stdlib.h>
int system(const char *cmdstr)
-
Hàm này gọi lệnh chứa trong cmdstr 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 shell thực thi lệnh:
$ sh –c <cmdstr>
16
-
Hàm system() trả về:
Mã lỗi 127 nếu không thể khởi động shell và thực thi lệnh được
Mã lỗi –1 nếu gặp lỗi khác
Ngược lại mã trả về sẽ là mã do <cmdstr> sau khi thực thi trả về
- Ví dụ 7-1: system.c

17
7.4.2. Thay thế tiến trình hiện hành với hàm exec()
-
Hàm exec() sẽ thay thế toàn bộ ảnh của tiến trình hiện tại {tiến trình A}
(bao gồm mã lệnh, dữ liệu, bảng mô tả file) bằng ảnh của một tiến trình
khác {tiến trình B}
-
Việc thay thế này chỉ giữ lại số PID của tiến trình A
-
Hàm thay thế ảnh của tiến trình bao gồm tập các hàm sau:
#include <unistd.h>
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 execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *file, char *const argv[],
char *const envp[]);
- Ví dụ 7-2: pexec.c
18
7.4.3. Nhân bản tiến trình với hàm fork()
-
Việc thay thế tiến trình đôi khi cũng bất lợi do tiến trình mới tạo ra
chiếm toàn bộ không gian của tiến trình cũ và không còn khả năng kiểm
soát tiến trình cũ nữa.
-
Sử dụng hàm fork() để nhân bản tiến trình.
-
Hàm fork() sẽ quay về nơi gọi hai lần với hai giá trị trả về khác nhau.

-
Cách thức khai báo:
#include <sys/types.h>
#include <unistd.h>
pid_t fork()
-
Hình 7.2 minh họa cách nhân bản
tiến trình bằng fork()
Hình 7.2
Cơ chế nhân bản tiến trình của fork()
Khởi tạo tiến trình
chính
Gọi fork()
Mã lệnh kế tiếp của
tiến trình ban đầu
(tiến trình cha)
Mã lệnh thực thi tiến
trình mới
(tiến trình con)
Trả về PID của tiến
trình con
Trả về trị 0
19
-
Đ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(); /*Nhân bản tiến trình*/
switch (new_pid) {
case –1:
printf(“Can not fork new process”);

break;
case 0:
printf(“This is child process”);
/*Mã lệnh dành cho tiến trình con*/
break;
default:
printf(“This is parent process”);
/* Mã lệnh dành cho tiến trình cha*/
break;
}
- Ví dụ 7-3: fork_demo.c
20
7.4.4. Kiểm soát và đợi tiến trình con
-
Hàm fork() nhân bản tiến trình hiện hành thành hai tiến trình cha và con
hoạt động độc lập với nhau.
-
Đôi khi tiến trình cha phải đợi tiến trình con thực thi xong tác vụ thì
mới được tiếp tục thực thi.
-
Giải quyết vấn đề này bằng hàm wait()
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
pid_t waitpid(pid_t pid,int *status,
int options)
-
Sử dụng một số macro được khai báo sẵn trong <sys/wait.h> để
diễn dịch một số trạng thái mà hàm wait() sẽ trả về (Tham khảo)
-

Ví dụ 7-4: wait_child.c và Ví dụ 7-5: wait_child2.c
21
7.4.5. Đón xử lý tín hiệu khi tiến trình con kết thúc
-
Tiến trình cha có thể đón bắt tín hiệu SIGCHLD khi tiến trình con
chấm dứt và gán cho nó một tác vụ thực thi nào đó. Bằng cách này, tiến
trình cha có thể không cần phải gọi wait() để chờ tiến trình con kết thúc
mới có thể thực thi được tác vụ tiếp theo.
-
Trong Ví dụ 7-6, hàm catch_child() dùng để xử lý tín hiệu (hay còn
được gọi là bộ xử lý tín hiệu)
-
Để gán một hàm xử lý tín hiệu cho một tín hiệu cụ thể nào đó  gọi
hàm hệ thống signal()
-
Ví dụ 7-6: child_signal.c
22
7.4.6. Thay thế hàm system()
-
Có thể viết lại hàm system() mà không cần phải triệu gọi lệnh thông qua
shell của hệ thống.
-
Ví dụ 7-7 kết hợp sử dụng hàm fork() với hàm thay thế ảnh của tiến
trình execlp()
-
Ví dụ 7-7: system2.c
23
7.4.7. Bỏ rơi tiến trình con
-
Là tình huống khi cả hai tiến trình cha và con cùng hoạt động độc lập

nhưng tiến trình cha kết thúc trước tiến trình con và đến khi tiến trình
con kết thúc thì sẽ không còn điểm trở về để liên hệ với tiến trình cha đã
sinh ra nó trước đó  Tiến trình con ở trạng thái zombie (bỏ rơi)
-
Linux sẽ tự động gán PPID của tiến trình con (đang ở trạng thái
zombie) về giá trị 1 (tiến trình init)
-
Ví dụ 7-8: zombie_child.c
24
7.4.8. Chuyển hướng xuất nhập của tiến trình
-
Mỗi tiến trình có một bảng mô tả tập tin riêng để lưu trữ thông tin về
các tập tin đang mở. Có thể tận dụng kỹ thuật này để xây dựng bộ lọc dữ
liệu bằng chuyển hướng xuất nhập.
-
Xét ví dụ đọc dữ liệu từ luồng nhập chuẩn stdin sau đó chuyển đổi dữ
liệu nhập được thành chữ hoa.
-
Ví dụ 7-9: upper.c
-
Ví dụ 7-10: dataupper.c
25
7.5. Đọc thông tin v
7.5. Đọc thông tin v




các tiến trình
các tiến trình

-
Tất cả các thông tin mà lệnh ps trả về được lấy trong thư mục /proc
-
Khi một tiến trình mới được tạo thì hệ thống sẽ tạo một thư mục con
bên trong thư mục /proc với tên là số PID của tiến trình và sẽ tự động
loại bỏ thư mục này khỏi /proc khi tiến trình trên kết thúc:
/proc
1  tiến trình init
1062  tiến trình khác
1123
1234
. . .
-
Trong từng thư mục con sẽ thấy một số tập tin ghi lại trạng thái của tiến
trình.
-
Có thể xây dựng một Process Manager dựa trên thông tin lấy từ thư
mục /proc

×