Professional Documents
Culture Documents
HỒ CHÍ MINH
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
o
HỆ ĐIỀU HÀNH
1. Sinh viên tham dự đầy đủ các buổi thực hành theo quy định
của giảng viên hướng dẫn (GVHD) (6 buổi với lớp thực
hành cách tuần hoặc 10 buổi với lớp thực hành liên tục).
2. Sinh viên phải chuẩn bị các nội dung trong phần “Sinh viên
viên chuẩn bị” trước khi đến lớp. GVHD sẽ kiểm tra bài
chuẩn bị của sinh viên trong 15 phút đầu của buổi học (nếu
không có bài chuẩn bị thì sinh viên bị tính vắng buổi thực
hành đó).
3. Sinh viên làm các bài tập ôn tập để được cộng điểm thực
hành, bài tập ôn tập sẽ được GVHD kiểm tra khi sinh viên
có yêu cầu trong buổi học liền sau bài thực hành đó. Điểm
cộng tối đa không quá 2 điểm cho mỗi bài thực hành.
Bài 5. ĐỒNG BỘ HÓA TIẾN TRÌNH, TIỂU
TRÌNH
Sinh viên thực hiện và hiểu được tầm quan trọng của việc
đồng bộ hóa tiến trình, tiểu trình.
Để thực hiện bài thực hành này, sinh viên phải đảm bảo những
điều sau:
Chức
Tên hàm Ghi chú Ví dụ
năng
Sử dụng #include Khai báo thêm thư viện gcc -o
thư viện <semaphore.h> pthread và rt khi biên dịch. filename
semapho filename.c -
-re lpthread -
lrt
Định sem_t sem_name; sem_t sem;
nghĩa 1
semapho
re có tên
2
là
sem_na
me
Khởi tạo int sem_init (sem_t *sem_name: con trỏ chỉ đến sem_t sem;
1 biến *sem_name, int địa chỉ của biến semaphore sem_init
semapho pshared, unsigned (được khai báo như trên). (&sem, 0,
-re int value); pshared: 10);
- Nếu được đặt là 0: biến
semaphore sẽ được chia sẻ
giữa các tiểu trình của cùng
1 tiến trình (và cần đặt ở nơi
mà tất cả các tiểu trình đều
có thể truy xuất được như
biến toàn cục hoặc biến
động).
- Nếu được đặt khác 0: biến
semaphore sẽ được chia sẻ
giữa những tiến trình với
nhau và cần được đặt ở vùng
nhớ được chia sẻ (shared
memory).
value: giá trị khởi tạo cho
semaphore là số không âm.
Giá trị trả về:
- Là 0 nếu thành công
- Là -1 nếu thất bại
Đợi 1 int sem_wait(sem_t - Nếu giá trị của semaphore sem_wait(
3
semapho *sem); = 0: tiến trình bị block cho &sem);
-re đến khi giá trị của
semaphore > 0 (để có thể trừ
đi 1). Lưu ý: giá trị của
semaphore không là số âm
(xem khai báo ở trên)
- Nếu giá trị của semaphore
> 0: giá trị của semaphore
trừ đi 1 và return, tiến trình
tiếp tục chạy.
Giá trị trả về:
- Là 0 nếu thành công.
- Là -1 nếu thất bại, giá trị
của semaphore không thay
đổi.
Mở int sem_post(sem_t Một trong các tiến trình/tiểu sem_post(
khóa 1 *sem); trình bị block bởi sem_wait &sem);
semapho sẽ được mở và sẵn sàng để
-re thực thi.
Giá trị trả về:
- Là 0 nếu thành công
- Là -1 nếu thất bại
Lấy giá int Lấy giá trị của semaphore và sem_getval
trị của 1 sem_getvalue(sem_t gán vào biến được xác định ue(&sem,
semapho *sem, int *valp); tại địa chỉ valp. &value);
-re Giá trị trả về: Biến value
- Là 0 nếu thành công lúc này có
4
- Là -1 nếu thất bại giá trị là
giá trị của
semaphore.
Hủy 1 int Hủy đi 1 biến semaphore. sem_destro
biến sem_destroy(sem_t Lưu ý: nếu đã quyết định y(&sem);
semapho *sem) hủy biến semaphore thì cần
-re chắc chắn là không còn tiến
trình/tiểu trình nào truy xuất
vào biến semaphore đó nữa.
Giá trị trả về:
- Là 0 nếu thành công
- Là -1 nếu thất bại
5.3.1.2. Ví dụ về semaphore
Ví dụ có 2 process được thực thi song song như sau:
PROCESS A PROCESS B
processA processB
{ {
while (true) while (true)
sells++; products++;
} }
Process A mô tả số lượng hàng bán được: sells
Process B mô tả số lượng sản phẩm được làm ra: products
Biết rằng ban đầu chúng ta chưa có hàng và cũng chưa bán
được gì: sells = products = 0
5
Do khả năng tạo ra hàng hóa và khả năng bán hàng là không
đồng đều, có lúc bán đắt thì sẽ sells tăng nhanh, lúc bán ế thì sells
tăng chậm lại. Lúc công nhân làm việc hiệu quả thì sẽ tạo ra
products nhanh, ngược lại lúc công nhân mệt thì sẽ làm ra
products chậm lại. Tuy nhiên, dù bán đắt hay ế, làm nhanh hay
chậm thì vẫn phải đảm bảo một điều là phải “có hàng thì mới bán
được”, nói cách khác ta phải đảm bảo: products >= sells.
Vậy yêu cầu đặt ra là sử dụng semaphore để đồng bộ 2 tiến
trình: A (bán hàng) và B (tạo ra hàng) theo điều kiện trên?
Phân tích bài toán trên ta thấy như sau:
PROCESS A muốn “bán hàng” thì phải kiểm tra xem liệu
có hàng để bán hay không?
6
while (true){ while (true){
sem_wait(&sem); products++;
sells++; sem_post(&sem);
} }
} }
Với 2 PROCESS A và PROCESS B, ta có 2 trường hợp như
sau:
PROCESS A nhanh hơn PROCESS B nhanh hơn
PROCESS B (bán nhanh hơn PROCESS A (làm nhanh hơn
làm) bán)
Mỗi khi PROCESS A muốn Sau khi PROCESS B tăng biến
tăng biến sells (bán hàng), nó sẽ products (làm ra hàng mới), nó
gặp hàm sem_wait(&sem) sẽ gọi hàm sem_post(&sem) để
trước, hàm này sẽ kiểm tra xem tăng giá trị của sem lên 1, lúc
giá trị của sem liệu có lớn hơn 0 này PROCESS A nếu như đang
(có hàng không). bị block do hàm sem_wait
+ Nếu sem.value = 0: trước đó sẽ được mở ra và sẵn
PROCESS A bị block không sàng để “bán hàng”.
bán nữa. PROCESS B chạy được 1 đoạn
+ Nếu sem.value > 0: thời gian sẽ phải nhường lại cho
PROCESS A được phép tăng PROCESS A, lúc này
sells (được phép bán hàng) và PROCESS A sẽ trừ giá trị của
giảm sem.value đi 1. sem đi 1 thông qua hàm
7
PROCESS A sau khi chạy được sem_wait, rồi sau đó mới tăng
1 đoạn thời gian sẽ được dừng giá trị của sells.
và chuyển cho PROCESS B
chạy (do quy tắc lập lịch của hệ
điều hành), lúc này PROCESS
B sẽ tăng products (làm ra
hàng) đồng thời tăng giá trị của
sem và sau đó khi tới phiên của
PROCESS A, nó sẽ có thể tăng
giá trị của sells (bán hàng).
5.3.2 Mutex
8
Các hàm cơ bản khi sử dụng Mutex
Để có thể sử dụng mutex, ta cần phải include thư viện
pthread.h.
Sau khi include thư viện trên, ta có thể sử dụng mutex thông
qua các hàm:
Chức
Tên hàm Ghi chú Ví dụ
năng
Khai pthread_mutex_t Thông thường mutex được pthread_mutex_t
báo 1 mutex_name khai như một biến toàn cục mutex;
mutex
có tên
là
mutex_
9
name
10
mutex unlock(pthread_ Sau khi mở khóa, các thread
mutex_t *mutex) khác sẽ được quyền tranh
chấp quyền khóa mutex.
Giá trị trả về:
- Là 0 nếu thành công
- Là -1 nếu thất bại
Hủy 1 int Hủy mutex được tham chiếu pthread_mutex_
mutex pthread_mutex_ bởi con trỏ *mutex. destroy(&mutex)
destroy(pthread
_mutex_t
*mutex)
Sinh viên chuẩn bị câu trả lời cho những câu hỏi sau trước khi
bắt đầu phần thực hành:
Phân biệt các khái niệm chương trình (program), tiến trình
(process) và tiểu trình (thread)?
11
5.4 Hướng dẫn thực hành
Thread còn lại lấy ra một phần tử trong a (phần tử bất kỳ,
phụ thuộc vào người lập trình). Sau đó đếm và xuất ra số
phần tử của a có được ngay sau khi lấy ra, nếu không có
phần tử nào trong a thì xuất ra màn hình “Nothing in array
a”.
Chạy thử và tìm ra lỗi khi chạy chương trình trên khi chưa
được đồng bộ. Thực hiện đồng bộ hóa với semaphore.
3. Cho 2 process A và B chạy song song như sau:
int x = 0;
PROCESS A PROCESS B
processA() processB()
{ {
12
while(1){ while(1){
x = x + 1; x = x + 1;
if (x == 20) if (x == 20)
x = 0; x = 0;
print(x); print(x);
} }
} }
Hiện thực mô hình trên C trong hệ điều hành Linux và
nhận xét kết quả.
4. Đồng bộ với mutex để sửa lỗi bất hợp lý trong kết quả của
mô hình Bài 3.
1. Biến ans được tính từ các biến x1, x2, x3, x4, x5, x6 như sau:
w = x1 * x2; (a)
v = x3 * x4; (b)
y = v * x5; (c)
z = v * x6; (d)
y = w * y; (e)
z = w * z; (f)
ans = y + z; (g)
Giả sử các lệnh từ (a) → (g) nằm trên các thread chạy song
song với nhau. Hãy lập trình mô phỏng và đồng bộ trên C
trong hệ điều hành Linux theo thứ tự sau:
13
(c), (d) chỉ được thực hiện sau khi v được tính
14