Một số bài toán đồng bộ

Một phần của tài liệu Giáo trình môn Hệ Điều Hành PTIT (Trang 74)

Để tiện minh họa cho việc sử dụng giải pháp đồng bộ, trong phần này sẽ trình bày một số bài toán đồng bộ kinh điển. Đây là những bài toán hoặc có ứng dụng trên thực tế hoặc không có ứng dụng nhưng rất thuận tiện trong việc mô tả vấn đề xảy ra giữa các quá trình đồng thời và do vậy thường được sử dụng để minh họa hoặc kiểm tra giải pháp đồng bộ hóa.

a. Bài toán triết gia ăn cơm

Tình huống trong bài toán như sau. Có năm triết gia ngồi trên ghế quanh một bàn tròn, giữa bàn là thức ăn, xung quanh bàn có năm chiếc đũa sao cho bên phải mỗi người có một đũa và bên trái có một đũa (hình 2.16).

Hình 2.16. Bài toán các triết gia ăn cơm

Công việc của mỗi triết gia là suy nghĩ. Khi người nào đó cần ăn, người đó dừng suy nghĩ, nhặt hai chiếc đũa nằm gần hai phía và ăn. Triết gia có thể nhặt hai chiếc đũa theo thứ tự bất kỳ nhưng bắt buộc phải nhặt từng chiếc một với điều kiện đũa không nằm trong tay người khác. Sau khi cầm được cả hai đũa, triết gia bắt đầu ăn và không đặt đũa xuống trong thời gian ăn. Sau khi ăn xong, triết gia đặt hai đũa xuống bàn và suy nghĩ tiếp.

Có thể coi năm triết gia như năm tiến trình đồng thời với tài nguyên nguy hiểm là đũa và đoạn nguy hiểm là đoạn dùng đũa để ăn.

Cờ hiệu cho phép giải quyết bài toán này như sau. Mỗi đũa được biểu diễn bằng một cờ hiệu. Thao tác nhặt đũa sẽ gọi Wait đối với cờ hiệu tương ứng và thao tác đặt đũa xuống bàn gọi Signal. Toàn bộ giải pháp sử dụng cờ hiệu cho bài toán triết gia ăn cơm thể hiện trên 2.17.

semaphore chopstick[5] = {1,1,1,1,1,1};

void Philosopher(int i){ //tiến trình P(i)

for(;;){ //lặp vô hạn

Wait(chopstick[i]); //lấy đũa bên trái

Wait(chopstick[(i+1)%5]); //lấy đũa bên phải <Ăn cơm> Signal(chopstick[(i+1)%5]); Signal(chopstick[i]); <Suy nghĩ> } } void main(){ PTIT

// chạy đồng thời 5 tiến trình StartProcess(Philosopher(1)); ...

StartProcess(Philosopher (5)); }

Hình 2.17. Bài toán triết gia ăn cơm sử dụng cờ hiệu

Lưu ý rằng giải pháp trên 2.17 cho phép thực hiện loại trừ tương hỗ, tức là tránh trường hợp hai triết gia cùng nhặt một đũa. Tuy nhiên, giải pháp này có thể gây bế tắc nếu cả năm người cùng nhặt được đũa bên trái và không thể tiếp tục vì đũa bên phải đã bị người bên phải nhặt mất. Cách giải quyết tình trạng này sẽ được đề cập trong phần về bế tắc.

b. Bài toán người sản xuất, người tiêu dùng với bộ đệm hạn chế

Bài toán được mô tả như sau. Có một người sản xuất ra sản phẩm gì đó và xếp sản phẩm làm ra vào một chỗ chứa gọi là bộ đệm, mỗi lần một sản phẩm. Một người tiêu dùng lấy sản phẩm từ bộ đệm, mỗi lần một sản phẩm, để sử dụng. Dung lượng của bộ đệm là hạn chế và chỉ chứa được tối đa N sản phẩm. Đây là bài toán có nhiều phiên bản tương tự trên thực tế, chẳng hạn thiết bị vào ra như bàn phím có thể nhận ký tự gõ từ bàn phím, đặt vào bộ đệm, và tiến trình lấy ký tự từ bộ đệm ra để xử lý. Trong trường hợp tổng quát có thể có nhiều người sản xuất cùng làm ra và xếp sản phẩm vào bộ đệm.

Bài toán người sản xuất người tiêu dùng đặt ra ba yêu cầu đồng bộ sau:

- Người sản xuất và người tiêu dùng không được sử dụng bộ đệm cùng một lúc. Đây là yêu cầu loại trừ tương hỗ.

- Khi bộ đệm rỗng, người tiêu dùng không nên cố lấy sản phẩm.

- Khi bộ đệm đầy, người sản xuất không được thêm sản phẩm vào bộ đệm.

Ba yêu cầu trên có thể giải quyết bằng cờ hiệu. Yêu cầu thứ nhất được giải quyết bằng cách sử dụng một cờ hiệu lock khởi tạo bằng 1. Yêu cầu thứ hai và thứ ba được giải quyết lần lượt bằng hai cờ hiệu empty và full. Cờ hiệu empty được khởi tạo bằng 0 và full

được khởi tạo bằng kích thước bộ đệm N. Giải pháp cho bài toán được thể hiện trên 2.18: const int N; //kích thước bộ đệm

semaphore lock = 1; semaphore empty = 0; semaphore full = N;

void producer () { //tiến trình người sản xuất for (;;) { <sản xuất > wait (full); wait (lock); <thêm một sản phẩm vào bộ đệm> signal (lock); PTIT

signal (empty); }

}

void consumer () { //tiến trình người tiêu dùng for (;;) { wait (empty); wait (lock); <lấy một sản phẩm từ bộ đệm> signal (lock); signal (full); <tiêu dùng> } } void main(){ StartProcess(producer); StartProcess(consumer); }

Hình 2.18: Giải pháp cho bài toán người sản xuất người tiêu dùng sử dụng cờ hiệu

Một phần của tài liệu Giáo trình môn Hệ Điều Hành PTIT (Trang 74)