Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

Khoa Kỹ thuật máy tính - UIT

BÁO CÁO THỰC HÀNH


Môn học: Hệ điều hành
Bài báo cáo: Lab 03

THÔNG TIN CHUNG:

Lớp: IT007.O212.2

Họ và tên MSSV
Nguyễn Quốc An 22520023

1. Làm bài nội dung 3.5


1.1. Thực hiện Ví dụ 3-1, Ví dụ 3-2, Ví dụ 3-3, Ví dụ 3-4 giải thích code và kết quả
nhận được?
Ví dụ 3-1: test_fork.c
• #include<stdlib.h>: Thư viện này chứa các hàm và biến môi trường, quản lý bộ nhớ, chuỗi và
các hàm khác.
• #include<unistd.h>: Thư viện này chứa các hàm POSIX (Portable Operating System
Interface), bao gồm fork() và getpid().
• #include<sys/wait.h>: Thư viện này chứa các định nghĩa cho việc chờ (wait) các tiến trình con.
• #include<sys/types.h>: Thư viện này chứa các kiểu dữ liệu, bao gồm __pid_t dùng để lưu trữ
ID của tiến trình.
• __pid_t pid: Khai báo một biến pid kiểu __pid_t để lưu trữ ID của tiến trình.
• pid = fork(): Gọi hàm fork() để tạo ra một tiến trình con. ID của tiến trình con được lưu trong
biến pid.
• if (pid > 0) {printf("PARENTS | PID = %ld | PPID = %ld\n",(long)getpid(), (long)getppid()); if
(argc > 2)printf("PARENTS | There are %d arguments\n",argc - 1); wait(NULL);}: Nếu chỉ số pid
> 0, đoạn code trong khối này sẽ được thực thi bởi tiến trình cha. Tiến trình cha sẽ in ra ID của
nó và ID của tiến trình cha của nó. Nếu có nhiều hơn 2 đối số, tiến trình cha cũng sẽ in ra số
lượng đối số. Sau đó, tiến trình cha sẽ chờ tiến trình con kết thúc bằng cách gọi wait(NULL).
• if (pid == 0) {printf("CHILDREN | PID = %ld | PPID = %ld\n", (long)getpid(), (long)getppid());
printf("CHILDREN | List of arguments: \n"); for (int i = 1; i < argc; i++){printf("%s\n", argv[i]);}}:
Nếu pid == 0, đoạn code trong khối này sẽ được thực thi bởi tiến trình con. Tiến trình con sẽ in
ra ID của nó và ID của tiến trình cha của nó, cũng như danh sách các đối số được truyền vào
chương trình.
• exit(0): Cuối cùng, cả tiến trình cha và tiến trình con đều gọi exit(0); để kết thúc chương trình
với mã trạng thái 0, cho biết chương trình đã kết thúc thành công.
• PARENTS | PID = 20905 | PPID = 12992: Đây là thông báo từ tiến trình cha. PID = 20905
cho biết ID của tiến trình cha là 20905 và PPID = 12992 cho biết ID của tiến trình cha của
tiến trình cha (tức là tiến trình đã tạo ra tiến trình cha) là 12992 (hay còn gọi là Shell).
• PARENTS | There are 3 arguments: Tiến trình cha cũng thông báo rằng có 3 đối số được
truyền vào chương trình (1, 2, và 3).
• CHILDREN | PID = 20906 | PPID = 20905: Đây là thông báo từ tiến trình con. PID = 20906
cho biết ID của tiến trình con là 20906 và PPID = 20905 cho biết ID của tiến trình cha của
tiến trình con (tức là tiến trình cha) là 20905.
• CHILDREN | List of arguments: 1 2 3: Tiến trình con sau đó in ra danh sách các đối số
được truyền vào chương trình.

Ví dụ 3-2: test_execl.c

• __pid_t pid: Khai báo một biến pid kiểu __pid_t để lưu trữ ID của tiến trình.
• pid = fork(): Gọi hàm fork() để tạo ra một tiến trình con. ID của tiến trình con được lưu trong
biến pid.
• if (pid > 0){printf("PARENTS | PID = %ld | PPID = %ld\n",(long)getpid(), (long)getppid()); if
(argc > 2) printf("PARENTS | There are %d arguments\n",argc - 1); wait(NULL);}: Nếu chỉ
số pid > 0, đoạn code trong khối này sẽ được thực thi bởi tiến trình cha. Tiến trình cha sẽ
in ra ID của nó và ID của tiến trình cha của nó. Nếu có nhiều hơn 2 đối số, tiến trình cha
cũng sẽ in ra số lượng đối số. Sau đó, tiến trình cha sẽ chờ tiến trình con kết thúc bằng
cách gọi wait(NULL).
• if (pid == 0){execl("./count.sh", "./count.sh", "10", NULL); printf("CHILDREN | PID = %ld |
PPID = %ld\n", (long)getpid(), (long)getppid()); printf("CHILDREN | List of arguments: \n");
for (int i = 1; i < argc; i++){printf("%s\n", argv[i]);}}: Nếu chỉ số pid == 0, đoạn code trong
khối này sẽ được thực thi bởi tiến trình con. Tiến trình con sẽ thực thi file count.sh với đối
số là "10" bằng cách gọi excel với câu lệnh execl("./count.sh", "./count.sh", "10", NULL).
Sau khi gọi hàm execl(), tiến trình hiện tại sẽ bị thay thế bằng tiến trình mới, do đó các
dòng code sau execl() sẽ không được thực thi.

• PARENTS | PID = 25375 | PPID = 12992: Đây là thông điệp in ra từ tiến trình cha. Nó cho
biết rằng PID của tiến trình cha là 25375 và PPID là 12992.
• PARENTS | There are 3 arguments: Đây là thông điệp in ra từ tiến trình cha. Nó cho biết
rằng có 3 đối số được truyền vào chương trình.
• Implementing: ./count.sh: Đây là thông điệp in ra từ tiến trình con sau khi gọi hàm execl
để thực thi tập lệnh shell từ file count.sh.
• PPID of count.sh: Đây là kết quả của lệnh ps -ef | grep count.sh được thực thi trong tiến
trình con. Nó cho biết PPID của tiến trình con count.sh là 25375, giống với PID của tiến
trình cha.
• quocan 25376 25375 0 19:54 pts/3 00:00:00 /bin/bash ./count.sh 10
quocan 25378 25376 0 19:54 pts/3 00:00:00 grep count.sh: Là kết quả của lệnh ps -ef |
grep count.sh, nó hiển thị thông tin về các tiến trình liên quan đến tập lệnh count.sh.

Ví dụ 3-3: test_system.c

• printf("PARENTS | PID = %ld | PPID = %ld\n", (long)getpid(), (long)getppid()): In ra ID của


tiến trình cha và ID của tiến trình cha của tiến trình cha.
• if (argc > 2) printf("PARENTS | There are %d arguments\n", argc - 1): Nếu có nhiều hơn 2
đối số, tiến trình trình cha sẽ in ra số lượng đối số.
• system("./count.sh 10"): Gọi hàm system() để thực thi file count.sh với đối số là "10". Hàm
system() sẽ tạo ra một tiến trình con để thực thi lệnh hoặc chương trình được chỉ định,
trong trường hợp này là count.sh.
• printf("PARENTS | List of arguments: \n"); for (int i = 1; i < argc; i++) { printf("%s\n",
argv[i]); }: In ra danh sách các đối số được truyền vào chương trình.
• exit(0): Kết thúc chương trình với mã trạng thái 0, cho biết chương trình đã kết thúc thành
công.
• PARENTS | PID = 27781 | PPID = 12992: PID = 27781 cho biết ID của tiến trình cha là
27781 và PPID = 12992 cho biết ID của tiến trình cha của tiến trình cha (tức là shell) là
12992.
• PARENTS | There are 3 arguments: Quá trình cha cũng thông báo rằng có 3 đối số được
truyền vào chương trình (1, 2, và 3).
• Implementing: ./count.sh: Đây là thông báo từ script count.sh, cho biết script đang được
thực thi.
• PPID of count.sh:
quocan 27782 27781 0 20:02 pts/3 00:00:00 sh -c ./count.sh 10
quocan 27783 27782 0 20:02 pts/3 00:00:00 /bin/bash ./count.sh 10
quocan 27785 27783 0 20:02 pts/3 00:00:00 grep count.sh: Đây là kết quả của lệnh ps -ef
| grep count.sh trong file count.sh, hiển thị các quá trình liên quan đến count.sh.
• PARENTS | List of arguments: 1 2 3: Cuối cùng, tiến trình cha in ra danh sách các đối số
được truyền vào chương trình.

Ví dụ 3-4: test_shm
a) Process A:
test_shm_A.c

• #include < fcntl.h>: Chứa các hằng số và cấu trúc dùng cho việc mở, tạo file và thao tác
file.
• #include <sys/shm.h>: Chứa các hàm và cấu trúc dùng cho việc tạo và quản lý shared
memory.
• #include <sys/stat.h>: Chứa các cấu trúc và hằng số dùng cho việc lấy thông tin về file và
thư mục.
• #include <sys/mman.h>: Chứa các hàm và hằng số liên quan đến quản lý bộ nhớ, bao
gồm hàm mmap() và munmap() để thao tác với các phân vùng bộ nhớ được ánh xạ.
• const int SIZE = 4096: Khởi tạo kích thước của vùng nhớ chia sẻ.
• const char *name = "OS": Khởi tạo tên của vùng nhớ chia sẻ.
• int fd: File descriptor của vùng nhớ chia sẻ.
• char *ptr: Con trỏ trỏ đến vùng nhớ chia sẻ.
• fd = shm_open(name, O_CREAT | O_RDWR, 0666): Tạo vùng nhớ chia sẻ với name: định
danh của vùng nhớ được chia sẻ, O_CREATE|O_RDRW: yêu cầu tạo đối tượng vùng
• nhớ chia sẻ nếu chưa tồn tại và mở với chế độ đọc và
• ghi và 0666: chế độ trên vùng nhớ chia sẻ.
• ftruncate(fd, SIZE): Thiết lập kích thước cho vùng nhớ chia sẻ.
• ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0): Ánh xạ vùng
nhớ chia sẻ vào không gian bộ nhớ của tiến trình với 0: địa chỉ vùng nhớ bắt đầu ánh xạ,
SIZE: kích thước vùng nhớ, PROT_READ | PROT_WRITE: chế độ bảo vệ cho phép đọc
và ghi, MAP_SHARED: chế độ chia sẻ những thay đổi trên bộ nhớ với các tiến trình khác,
fd: đối tượng bộ nhớ chia sẻ và 0: Offset (độ dời) trên file, chỉ vị trí nhớ bắt đầu ánh
• xạ.
• sprintf(ptr, "Hello Process B"): Ghi dữ liệu vào vùng nhớ chia sẻ.
• while (strncmp(ptr, "Hello Process B", 15) == 0) {printf("Waiting Process B update shared
memory\n"); sleep(1);}: Chờ cho đến khi Process B cập nhật vùng nhớ chia sẻ.
• munmap(ptr, SIZE); close(fd) : Hủy ánh xạ vùng nhớ chia sẻ và đóng file descriptor.

• "Waiting Process B update shared memory" được in ra màn hình mỗi giây một lần cho
đến khi Process B cập nhật vùng nhớ chia sẻ..
b) Process B:
test_shm_B.c
• const int SIZE = 4096: Khởi tạo kích thước (tính bằng byte) của vùng nhớ chia sẻ.
• const char *name = "OS": Khởi tạo tên của vùng nhớ chia sẻ.
• int fd: Khởi tạo File descriptor của vùng nhớ chia sẻ.
• char *ptr: Con trỏ đến đối tượng vùng nhớ chia sẻ.
• fd = shm_open(name, O_RDWR,0666): Tạo đối tượng vùng nhớ chia sẻ.
• ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0): Ánh xạ vùng
nhớ chia sẻ.
• printf("Read shared memory: "); printf("%s\n",(char *)ptr): Đọc từ vùng nhớ chia sẻ.
• strcpy(ptr, "Hello Process A"); printf("Vùng nhớ chia sẻ đã được cập nhật: %s\n", ptr): Cập
nhật vùng nhớ chia sẻ.
• sleep(5): Dừng chương trình trong 5s.
• munmap(ptr, SIZE); close(fd): Hủy ánh xạ vùng nhớ chia sẻ và đóng file descriptor.
• shm_unlink(name): Loại bỏ vùng nhớ chia sẻ.

• Read shared memory: Hello Process B: Nội dung của vùng nhớ chia sẻ đã được đọc và
hiện tại là "Hello Process B".
• Shared memory updated: Hello Process A: Nội dung của vùng nhớ chia sẻ đã được cập
nhật thành "Hello Process A" bởi chương trình test_shm_A.
1.2. Viết chương trình time.c thực hiện đo thời gian thực thi của một lệnh shell.
Chương trình sẽ được chạy với cú pháp "./time <command>" với <command>
là lệnh shell muốn đo thời gian thực thi.

1.3. Viết một chương trình làm bốn công việc sau theo thứ tự:
• In ra dòng chữ: “Welcome to IT007, I am <your_Student_ID>!”
• Thực thi file script count.sh với số lần đếm là 120
• Trước khi count.sh đếm đến 120, bấm CTRL+C để dừng tiến trình này
• Khi người dùng nhấn CTRL+C thì in ra dòng chữ: “count.sh has
stopped”
1.4. Viết chương trình mô phỏng bài toán Producer - Consumer như sau:
Sử dụng kỹ thuật shared-memory để tạo một bounded-buffer có độ lớn là 10
bytes.
Tiến trình cha đóng vai trò là Producer, tạo một số ngẫu nhiên trong khoảng
[10, 20] và ghi dữ liệu vào buffer
Tiến trình con đóng vai trò là Consumer đọc dữ liệu từ buffer, in ra màn hình
và tính tổng
Khi tổng lớn hơn 100 thì cả 2 dừng lại
2. Làm bài tập 3.6
Phỏng đoán Collatz xem xét chuyện gì sẽ xảy ra nếu ta lấy một số nguyên dương bất kỳ và áp
dụng theo thuật toán sau đây:

𝒏
, 𝒏ế𝒖 𝒏 𝒍à 𝒔ố 𝒄𝒉ẵ𝒏
𝒏 = {𝟐
𝟑 ∗ 𝒏 + 𝟏, 𝒏ế𝒖 𝒏 𝒍à 𝒔ố 𝒍ẻ
Phỏng đoán phát biểu rằng khi thuật toán này được áp dụng liên tục, tất cả số nguyên dương đều
sẽ tiến đến 1. Ví dụ, với n = 35, ta sẽ có chuỗi kết quả như sau:
35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1
Viết chương trình C sử dụng hàm fork() để tạo ra chuỗi này trong tiến trình con. Số bắt đầu sẽ
được truyền từ dòng lệnh. Ví dụ lệnh thực thi ./collatz 8 sẽ chạy thuật toán trên n = 8 và chuỗi kết
quả sẽ ra là 8, 4, 2, 1. Khi thực hiện, tiến trình cha và tiến trình con chia sẻ một buffer, sử dụng
phương pháp bộ nhớ chia sẻ, hãy tính toán chuỗi trên tiến trình con, ghi kết quả vào buffer và
dùng tiến trình cha để in kết quả ra màn hình. Lưu ý, hãy nhớ thực hiện các thao tác để kiểm tra
input là số nguyên dương.

You might also like