2.1. Khái niệm tiến trình ................................................................................................. 212.3. Các thao tác điều khiển tiến trình ............................................................................ 282.4. Giao tiếp giữa các tiến trình ..................................................................................... 302.5. Luồng (Thread) ........................................................................................................3.1. Các khái niệm cơ bản ............................................................................................... 393.2. Tiêu chí lập lịch ....................................................................................................... 413.3. Các thuật toán lập lịch ............................................................................................. 423.4. Lập lịch trên hệ thống nhiều CPU ...........................................................................4.1. Các khái niệm cơ bản ............................................................................................... 494.2. Các giải pháp phần mềm .......................................................................................... 514.3. Các giải pháp phần cứng ......................................................................................... 544.4. Semaphores .............................................................................................................. 554.5. Các bài toán đồng bộ kinh điển ................................................................................ 584.6. Monitors ...................................................................................................................5.1. Mô hình hệ thống ..................................................................................................... 645.2. Các phương pháp giải quyết bế tắc .......................................................................... 675.3. Ngăn bế tắc .............................................................................................................. 675.4. Tránh bế tắc ............................................................................................................. 685.5. Phát hiện bế tắc ........................................................................................................ 725.6. Phục hồi khỏi bế tắc .................................................................................................
Trang 1CHƯƠNG 2 QUẢN LÝ TIẾN TRÌNH 2.1 Khái niệm tiến trình
2.1.1 Tiến trình và các loại tiến trình
a Tiến trình (process):
Tiến trình là một khái niệm cơ bản trong hệ điều hành Tiến trình là một chương trình đang chạy Mỗi tiến trình có không gian địa chỉ riêng (address space), đó là vùng bộ nhớ dành riêng cho tiến trình, tiến trình có thể đọc và ghi trong vùng bộ nhớ này Vùng bộ nhớ này chứa chương trình, dữ liệu của chương trình và stack
Trong hệ thống chia xẻ thời gian (timesharing system), hệ điều hành định kỳ ngưng tạm thời (treo, suspend) một tiến trình đang chạy và cho một tiến trình khác chạy
Khi tiến trình được chạy lại, tiến trình được khôi phục lại trạng thái giống như trước khi
bị ngưng, do vậy tất cả các thông tin về tiến trình sẽ được cất giữ trước khi bị treo Các thông
tin này được lưu trong bảng điều hành (operating system table) của hệ điều hành, mỗi mục
trong bảng điều hành chứa thông tin của một tiến trình
Hàm gọi hệ thống liên quan đến tiến trình về cơ bản gồm có tạo tiến trình và chấm dứt tiến trình Một tiến trình có thể tạo những tiến trình khác, các tiến trình này được gọi là tiến
trình con (child process), và ta có một cây tiến trình
Hình 2.1 Cây tiến trình
Mỗi người được quyền sử dụng hệ thống sẽ có một số hiệu nhận diện UID (User
Identification), chỉ có người quản trị hệ thống mới được quyền gán UID cho người sử dụng
Tiến trình khi chạy mang UID của người sử dụng chạy nó Tiến trình con sẽ có UID giống như tiến trình cha Người sử dụng có thể thuộc một nhóm nào đó và cũng có số hiệu nhận
diện nhóm GID (Group Identification)
Trong hệ thống có một UID quan trọng, được gọi là superuser, có quyền cao nhất Chỉ
có người quản trị hệ thống mới có mật khẩu để trở thành superuser Superuser có thể vi phạm bất cứ sự bảo vệ an toàn hệ thống
b Các 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 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:
Trang 2Tiế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 qua 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à không khai thác tối đa thời gian xử lý của CPU 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 một CPU và nhiều CPU Nhưng sự song song thực, chỉ có ở các hệ thống nhiều CPU, trong hệ thống này mỗi CPU 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 một CPU 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 CPU, tiến trình này đang chạy thì có thể dừng lại để nhường CPU cho tiến trình khác chạy và sẽ tiếp tục lại sau đó khi có được CPU Đâ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 một CPU với các tiến trình song song/ đồng thời trong hệ
Trang 3thố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
2.1.2 Mô hình tiến trình
Đa số các hệ điều hành đều muốn đưa sự đa chương, đa nhiệm vào hệ thống Tức là, trong hệ thống có thể có nhiều chương trình hoạt động đồng thời (concurrence) với nhau Về nguyên tắc, để thực hiện được điều này thì hệ thống phải có nhiều CPU, mỗi CPU có nhiệm
vụ thực hiện một chương trình, nhưng mong muốn của hệ điều hành cũng như người sử dụng
là thực hiện sự đa chương trên các hệ thống chỉ có một CPU, và trên thực tế đã xuất hiện
nhiều hệ điều hành thực hiện được điều này, hệ điều hành windows9x, windowsNT/2000 chạy trên máy tính cá nhân là một ví dụ Để thực hiện được điều này hệ điều hành đã sử dụng
mô hình tiến trình để tạo ra sự song song giả hay tạo ra các CPU logic từ CPU vật lý Các CPU logic có thể hoạt động song song với nhau, mỗi CPU logic chịu trách nhiệm thực hiện một tiến trình
Trong mô hình tiến trình hệ điều hành chia chương trình thành nhiều tiến trình, khởi tạo
và đưa vào hệ thống nhiều tiến trình của một chương trình hoặc của nhiều chương trình khác nhau, cấp phát đầy đủ tài nguyên (trừ CPU) cho tiến trình và đưa các tiến trình sang trạng thái sẵn sàng Hệ điều hành bắt đầu cấp CPU cho một tiến trình trong số các tiến trình ở trạng thái sẵn sàng để tiến trình này hoạt động, sau một khoảng thời gian nào đó hệ điều hành thu hồi CPU của tiến trình này để cấp cho một tiến trình sẵn sàng khác, sau đó hệ điều hành lại thu hồi CPU từ tiến trình mà nó vừa cấp để cấp cho tiến trình khác, có thể là tiến trình mà trước đây bị hệ điều hành thu hồi CPU khi nó chưa kết thúc, và cứ như thế cho đến khi tất cả các tiến trình mà hệ điều hành khởi tạo đều hoạt động và kết thúc được Điều đáng chú ý trong mô hình tiến trình này là khoảng thời gian chuyển CPU từ tiến trình này sang tiến trình khác hay khoảng thời gian giữa hai lần được cấp phát CPU của một tiến trình là rất nhỏ nên các tiến trình có cảm giác luôn được sở hữu CPU (logic) hay hệ thống có cảm giác các tiến trình/ chương trình hoạt động song song nhau Hiện tượng này được gọi là sự song song giả
Giả sử trong hệ thống có 3 tiến trình sẵn sàng P1, P2, P3 thì quá trình chuyển CPU giữa 3
tiến trình này có thể minh họa như sau:
P1 P2
a
P1 P2
b
Hình 2.2: Sự thực hiện đồng thời của các tiến trình trong
hệ thống một CPU (a) và hệ thống nhiều CPU (b)
Trang 4Thời điểm Trạng thái các tiến trình
t1 P1: được cấp CPU t2 P1: bị thu hồi CPU (khi chưa kết thúc) P3: được cấp CPU
t3 P3: bị thu hồi CPU (khi chưa kết thúc)
P1: được cấp CPU t4 P1: kết thúc và trả lại CPU P2: được cấp CPU
t5 P2: kết thúc và trả lại CPU P3: được cấp CPU
t6 P3: kết thúc và trả lại CPU Hình 2.3 minh họa quá trình thực hiện của 3 tiến trình P1, P2, P3 ở trên:
Chúng ta đều biết, chức năng cở bản của CPU là thực hiện các chỉ thị máy (machine instrustion) thường trú trong bộ nhớ chính, các chỉ thị này được cung cấp từ một chương trình, chương trình bao gồm một dãy tuần tự các chỉ thị Và theo trên, tiến trình là một bộ phận của chương trình, nó cũng sở hữu một tập lệnh trong bộ nhớ chính, một con trỏ lệnh,… Nên xét về bản chất, thì việc chuyển CPU từ tiến trình này sang tiến trình khác thực chất là việc điều khển CPU để nó thực hiện xen kẽ các chỉ thị bên trong tiến trình Điều này có thể thực hiện dễ dàng bằng cách thay đổi hợp lý giá trị của con trỏ lệnh, đó chính là cặp thanh ghi CS:IP trong các CPU thuộc kiến trúc Intel, để con trỏ lệnh chỉ đến các chỉ thị cần thực hiện trong các tiến trình Để thấy rõ hơn điều này ta hãy xem ví dụ sau đây:
Giả sử hệ thống cần thực hiện đồng thời 3 tiến trình P1, P2, P3, bắt đầu từ tiến trình P1 Các chỉ thị của các tiến trình này được nạp vào bộ nhớ tại các địa chỉ như sau:
Tiến trình P1: Tiến trình P2: Tiến trình P3:
Trong đó: a: là địa chỉ bắt đầu của chương trình của tiến trình P1
b: là địa chỉ bắt đầu của chương trình của tiến trình P2
c: là địa chỉ bắt đầu của chương trình của tiến trình P3
Thì giá trị của con trỏ lệnh, chính xác là giá trị cặp thanh ghi CS:IP, lần lượt là: a + 0, b + 0, c + 0, a + 1, b + 2, c + 1, a + 3, b + 3, c + 4, a + 5, c + 6 Tức là, CPU thực hiện xen kẽ các chỉ thị của 3 tiến trình P1, P2, P3 từ lệnh đầu tiên đến lệnh cuối cùng, cho đến khi tất cả các chỉ thị của 3 tiến trình đều được thực hiện Nhưng khoảng thời gian từ khi con trỏ lệnh = a + 0 đến khi = a + 1, hay từ khi = b + 0 đến khi = b + 2, … là rất nhỏ, nên hệ thống có “cảm giác” 3 tiến trình P1, P2, P3 hoạt động đồng thời với nhau
Trang 5Ví dụ trên đây cho ta thấy bản chất của việc thực hiện song song (hay đồng thời) các tiến trình trên các hệ thống một CPU
Rõ ràng với mô hình tiến trình hệ thống có được 2 điều lợi:
Tiết kiệm được bộ nhớ: vì không phải nạp tất cả chương trình vào bộ nhớ mà chỉ nạp các tiến trình cần thiết nhất, sau đó tùy theo yêu cầu mà có thể nạp tiếp các tiến trình khác Cho phép các chương trình hoạt động song song nên tốc độ xử lý của toàn hệ thống tăng lên và khai thác tối đa thời gian xử lý của CPU
Việc chọn thời điểm dừng của tiến trình đang hoạt động (đang chiến giữ CPU) để thu hồi CPU chuyển cho tiến trình khác hay việc chọn tiến trình tiếp theo nào trong số các tiến trình đang ở trạng thái sẵn sàng để cấp CPU là những vấn đề khá phức tạp đòi hỏi hệ điều hành phải có một cơ chế điều phối thích hợp thì mới có thể tạo ra được hiệu ứng song song giả và sử dụng tối ưu thời gian xử lý của CPU Bộ phận thực hiện chức năng này của hệ điều hành được gọi là bộ điều phối (dispatcher) tiến trình
2.1.3 Khối quản lý tiến trình (Proccess Control Block – PCB)
Để quản lý các tiến trình và tài nguyên trong hệ thống, hệ điều hành phải có các thông tin về trạng thái hiện thời của mỗi tiến trình và tài nguyên Trong trường hợp này hệ điều hành xây dựng và duy trì các bảng thông tin về mỗi đối tượng (memory, devices, file, process) mà
nó quản lý, đó là các bảng: memory table cho đối tượng bộ nhớ, I/O table cho đối tượng thiết
bị vào/ra, file table cho đối tượng tập tin, process table cho đối tượng tiến trình Memory table được sử dụng để theo dõi cả bộ nhớ thực lẫn bộ nhớ ảo, nó phải bao gồm các thông tin sau: Không gian bộ nhớ chính dành cho tiến trình Không gian bộ nhớ phụ dành cho tiến trình Các thuộc tính bảo vệ bộ nhớ chính và bộ nhớ ảo Các thông tin cần thiết để quản lý bộ nhớ ảo Ở đây chúng tôi điểm qua một vài thông tin về memory table, là để lưu ý với các bạn rằng: nhiệm vụ quản lý tiến trình và quản lý bộ nhớ của hệ điều hành có quan hệ chéo với nhau, bộ phận quản lý tiến trình cần phải có các thông tin về bộ nhớ để điều khiển sự hoạt động của tiến trình, ngược lại bộ phận quản lý bộ nhớ phải có các thông tin về tiến trình để tổ chức nạp tiến trình vào bộ nhớ, … Điều này cũng đúng với các bộ phận quản lý vào/ ra và quản lý tập tin Trong phần trình bày sau đây chúng tôi chỉ đề cập đến Process Table của hệ điều hành
Để quản lý và điều khiển được một tiến trình, thì hệ điều hành phải biết được vị trí nạp tiến trình trong bộ nhớ chính, phải biết được các thuộc tính của tiến trình cần thiết cho việc quản lý tiến trình của nó:
Định vị của tiến trình (process location): định vị của tiến trình phụ thuộc vào chiến
lược quản lý bộ nhớ đang sử dụng Trong trường hợp đơn giản nhất, tiến trình, hay chính xác hơn là hình ảnh tiến trình, được lưu giữa tại các khối nhớ liên tục trên bộ nhớ phụ (thường là đĩa), để tiến trình thực hiện được thì tiến trình phải được nạp vào bộ nhớ chính Do đó, hệ điều hành cần phải biết định vị của mỗi tiến trình trên đĩa và cho mỗi tiến trình đó trên bộ nhớ chính Trong một số chiến lược quản lý bộ nhớ, hệ điều hành chỉ cần nạp một phần tiến trình vào bộ nhớ chính, phần còn lại vẫn nằm trên đĩa Hay tiến trình đang ở trên bộ nhớ chính thì
có một phần bị swap-out ra lại đĩa, phần còn lại vẫn còn nằm ở bộ nhớ chính Trong các trường hợp này hệ điều hành phải theo dõi tiến trình để biết phần nào của tiến trình là đang ở trong bộ nhớ chính, phần nào của tiến trình là còn ở trên đĩa
Đa số các hệ điều hành hiện nay đều sử dụng chiến lược quản lý bộ nhớ mà trong đó
Trang 6không gian địa chỉ của tiến trình là một tập các block, các block này có thể không liên tiếp nhau Tùy theo chiến lược bộ nhớ sử dụng mà các block này có thể có chiều dài cố định (chiến lược phân phân trang bộ nhớ) hay thay đổi (chiến lược phân đoạn bộ nhớ) hay kết hợp
cả hai Hệ điều hành cho phép không nạp tất cả các trang (page) và/hoặc các đoạn (segment) của tiến trình vào bộ nhớ Do đó, process table phải được duy trì bởi hệ điều hành và phải cho biết vị trí của mỗi trang/ đoạn tiến trình trên hệ thống Những điều trên đây sẽ được làm rõ ở
phần chiến lược cấp phát bộ nhớ trong chương Quản lý bộ nhớ của giáo trình này
Các thuộc tính của tiến trình: Trong các hệ thống đa chương, thông tin về mỗi tiến
trình là rất cần cho công tác quản lý tiến trình của hệ điều hành, các thông tin này có thể thường trú trong khối quản lý tiến trình Các hệ điều hành khác nhau sẽ có cách tổ chức PCB khác nhau, ở đây chúng ta khảo sát một trường hợp chung nhất Các thông tin trong PCB có thể được chia thành ba nhóm chính:
Hình 2.4 Ví dụ một PCB
Định danh tiến trình (process number, process identification - PID): mỗi tiến trình được gán một định danh duy nhất để phân biệt với các tiến trình khác trong hệ thống Định danh của tiến trình có thể xuất hiện trong memory table, I/O table Khi tiến trình này truyền thông với tiến trình khác thì định danh tiến trình được sử dụng để hệ điều hành xác định tiến trình đích Khi tiến trình cho phép tạo ra tiến trình khác thì định danh được sử dụng để chỉ đến tiến trình cha và tiến trình con của mỗi tiến trình Tóm lại, các định danh có thể lưu trữ trong PCB bao gồm: định danh của tiến trình này, định danh của tiến trình tạo ra tiến trình này, định danh của người sử dụng
Thông tin trạng thái CPU (CPU state information): bao gồm các thanh ghi User-visible, các thanh ghi trạng thái và điều khiển, các con trỏ stack
Thông tin điều khiển tiến trình (process control information): bao gồm thông tin trạng thái và lập lịch, cấu trúc dữ liệu, truyền thông liên tiến trình, quyền truy cập tiến trình, quản lý
bộ nhớ, tài nguyên khởi tạo và tài nguyên sinh ra
PCB là một trong những cấu trúc dữ liệu trung tâm và quan trọng của hệ điều hành Mỗi PCB chứa tất cả các thông tin về tiến trình mà nó rất cần cho hệ điều hành Có nhiều modun thành phần trong hệ điều hành có thể read và/hoặc modified PCB như: lập lịch tiến trình, cấp phát tài nguyên cho tiến trình, ngắt tiến trình, v.v… Có thể nói các thiết lập trong PCB định
Trang 7nghĩa trạng thái của hệ điều hành
2.2 Các trạng thái tiến trình
Từ khi được đưa vào hệ thống cho đến khi kết thúc tiến trình tồn tại ở các trạng thái khác nhau Trạng thái của tiến trình tại một thời điểm được xác định bởi hoạt động hiện thời của tiến trình tại thời điểm đó Tiến trình có thể ở một trong các trạng thái sau:
Tạo mới (new): tiến trình vừa được tạo ra
Sẵn sàng (ready ): Ngay sau khi khởi tạo tiến trình, đưa tiến trình vào hệ thống và cấp phát đầy đủ tài nguyên (trừ CPU) cho tiến trình, hệ điều hành đưa tiến trình vào trạng thái ready Hay nói cách khác, trạng thái ready là trạng thái của một tiến trình trong hệ thống đang chờ được cấp CPU để bắt đầu thực hiện
Đang thực thi (running): Là trạng thái mà tiến trình đang được sở hữu CPU để hoạt động, hay nói cách khác là các chỉ thị của tiến trình đang được thực hiện/ xử lý bởi CPU Chờ (waitng): Là trạng thái mà tiến trình đang chờ để được cấp phát thêm tài nguyên,
để một sự kiện nào đó xảy ra, hay một quá trình vào/ra kết thúc
Kết thúc (terminated): Hoàn tất việc thực thi
Quá trình chuyển trạng thái của các tiến trình trong được mô tả bởi sơ đồ sau:
Hình 2.5 Sơ đồ chuyển trạng thái của tiến trình
Trong đó:
Admitted: Tiến trình được khởi tạo, được đưa vào hệ thống, được cấp phát đầy đủ tài nguyên chỉ thiếu CPU
Scheduler dispatch: Tiến trình được cấp CPU để bắt đầu thực hiện/ xử lý
Exit: Tiến trình hoàn thành xử lý và kết thúc
Interrupt: Tiến trình bị bộ điều phối tiến trình thu hồi CPU, do hết thời gian được quyền
sử dụng CPU, để cấp phát cho tiến trình khác
I/O or event wait: Tiến trình đang chờ một sự kiện nào đó xảy ra hay đang chờ một thao vào/ra kết thúc hay tài nguyên mà tiến trình yêu cầu chưa được hệ điều hành đáp ứng
I/O or event completion: Sự kiện mà tiến trình chờ đã xảy ra, thao tác vào/ra mà tiến trình đợi đã kết thúc, hay tài nguyên mà tiến trình yêu cầu đã được hệ điều hành đáp ứng,
Trang 8Bộ phận điều phối tiến trình thu hồi CPU từ một tiến trình đang thực hiện trong các trường hợp sau:
- Tiến trình đang thực hiện hết thời gian (time-out) được quyền sử dụng CPU mà bộ phận điều phối dành cho nó
- Có một tiến trình mới phát sinh và tiến trình mới này có độ ưu tiên cao hơn tiến trình hiện tại
- Có một tiến trình mới phát sinh và tiến trình này mới cần một khoảng thời gian của CPU nhỏ hơn nhiều so với khoảng thời gian còn lại mà tiến trình hiện tại cần CPU
Tại một thời điểm xác định trong hệ thống có thể có nhiều tiến trình đang ở trạng thái ready hoặc waiting nhưng chỉ có một tiến trình ở trạng thái running Các tiến trình ở trạng thái ready và waiting được chứa trong các hàng đợi (queue) riêng
Có nhiều lý do để một tiến trình đang ở trạng thái running chuyển sang trạng thái waiting, do đó đa số các hệ điều hành đều thiết kế một hệ thống hàng đợi gồm nhiều hàng đợi,
mỗi hành đợi dùng để chứa những tiến trình đang đợi cùng một sự kiện nào đó
2.3 Các thao tác điều khiển tiến trình
2.3.1 Khởi tạo tiến trình
Khi tạo mới tiến trình hệ điều hành thực hiện các thao tác sau:
- Hệ điều hành gán PID cho tiến trình mới và đưa tiến trình vào danh sách quản lý của
hệ thống, tức là, dùng một entry trong PCB để chứa các thông tin liên quan đến tiến trình mới tạo ra này
- Cấp phát không gian bộ nhớ cho tiến trình Ở đây hệ điều hành cần phải xác định được kích thước của tiến trình, bao gồm code, data và stack Giá trị kích thước này có thể được gán mặt định dựa theo loại của tiến trình hoặc được gán theo yêu cầu của người sử dụng khi có một công việc (job) được tạo Nếu một tiến trình được sinh ra bởi một tiến trình khác, thì tiến trình cha có thể chuyển kích thước của nó đến hệ điều hành trong yêu cầu tạo tiến trình
- Khởi tạo các thông tin cần thiết cho khối điều khiển tiến trình như các PID của tiến trình cha (nếu có), thông tin trạng thái tiến trình, độ ưu tiên của tiến trình, thông tin ngữ cảnh của CPU (bộ đến chương trình và các thanh ghi khác), vv
- Cung cấp đầy đủ các tài nguyên cần thiết nhất, trừ CPU, để tiến trình có thể vào trạng thái ready được hoặc bắt đầu hoạt động được
- Đưa tiến trình vào một danh sách tiến trình nào đó: ready list, suspend list, waiting list,
vv, sao cho phù hợp với chiến lược điều phối tiến trình hiện tại của bộ phận điều phối tiến trình của hệ điều hành
Khi một tiến trình tạo lập một tiến trình con, tiến trình con có thể được cấp phát tài nguyên bởi chính hệ điều hành, hoặc được tiến trình cha cho thừa hưởng một số tài nguyên ban đầu của nó
2.3.2 Kết thúc tiến trình
Khi tiến trình kết thúc xử lý, hoàn thành chỉ thị cuối cùng, hệ điều hành sẽ thực hiện các
thao tác sau đây:
Trang 9- Thu hồi tài nguyên đã cấp phát cho tiến trình
- Loại bỏ tiến trình ra khỏi danh sách quản lý của hệ thống
- Huỷ bỏ khối điều khiển tiến trình
Hầu hết các hệ điều hành đều không cho phép tiến trình con hoạt động khi tiến trình cha
đã kết thúc Trong những trường hợp như thế hệ điều hành sẽ chủ động việc kết thúc tiến trình con khi tiến trình cha vừa kết thúc
2.3.3 Chuyển ngữ cảnh (context switch)
Muốn chuyển quyền sử dụng CPU giữa các tiến trình thì phải thay đổi tiến trình của các tiến trình Khi một tiến trình đang ở trạng thái running bị chuyển sang trạng thái khác (ready, waiting,…) thì hệ điều hành phải tạo ra sự thay đổi trong môi trường làm việc của nó, quá trình này được gọi là chuyển ngữ cảnh Sau đây là các bước mà hệ điều hành phải thực hiện đầy đủ khi thay đổi trạng thái tiến trình:
- Chọn một tiến trình khác để cho phép nó thực hiện
- Cập nhật PCB của tiến trình vừa được chọn thực hiện ở trên, chủ yếu là thay đổi trạng thái của tiến trình đến trạng thái running
Trang 10- Cập nhật các thông tin liên quan đến quản lý bộ nhớ Bước này phụ thuộc vào các yêu cầu chuyển đổi địa chỉ bộ nhớ đang được sử dụng
- Khôi phục (Restore) lại ngữ cảnh của CPU và thay đổi giá trị của bộ đếm chương trình
và các thanh ghi khác sao cho phù hợp với tiến trình được chọn ở trên, để tiến trình này có thể bắt đầu hoạt động được
Như vậy, khi hệ điều hành chuyển một tiến trình từ trạng thái running (đang chạy) sang một trạng thái nào đó (tạm dừng) thì hệ điều hành phải lưu trữ các thông tin cần thiết, nhất là Program Count, để sau này hệ điều hành có thể cho tiến trình tiếp tục hoạt động trở (tái kích hoạt) lại được Đồng thời hệ điều hành phải chọn một tiến trình nào đó đang ở trạng thái ready
để cho tiến trình này chạy (chuyển tiến trình sang trạng thái running) Tại đây, trong các thao tác phải thực hiện, hệ điều hành phải thực hiện việc thay đổi giá trị của PC, thay đổi ngữ cảnh CPU, để PC chỉ đến địa chỉ của chỉ thị đầu tiên của tiến trình running mới này trong bộ nhớ Đây cũng chính là bản chất của việc thực hiện các tiến trình trong các hệ thống một CPU
2.4 Giao tiếp giữa các tiến trình
2.4.1 Cộng tác giữa các tiến trình
Các tiến trình thực thi trong hệ điều hành có thể là những tiến trình độc lập hay những tiến trình cộng tác Một tiến trình là độc lập (independent) nếu nó không thể ảnh hưởng hay bị ảnh hưởng bởi các tiến trình khác thực thi trong hệ thống
Rõ ràng, bất kỳ một tiến trình không chia sẻ bất cứ dữ liệu (tạm thời hay cố định) với tiến trình khác là độc lập Ngược lại, một tiến trình là cộng tác (cooperating) nếu nó có thể ảnh hưởng hay bị ảnh hưởng bởi các tiến trình khác trong hệ thống Hay nói cách khác, bất cứ tiến trình chia sẻ dữ liệu với tiến trình khác là tiến trình cộng tác Chúng ta có thể cung cấp một môi trường cho phép cộng tác tiến trình với nhiều lý do:
- Chia sẻ thông tin: vì nhiều người dùng có thể quan tâm cùng phần thông tin (thí dụ, tập tin chia sẻ), chúng phải cung cấp một môi trường cho phép truy xuất đồng hành tới những loại tài nguyên này
- Gia tăng tốc độ tính toán: nếu chúng ta muốn một tác vụ chạy nhanh hơn, chúng ta phải chia nó thành những tác vụ nhỏ hơn, mỗi tác vụ sẽ thực thi song song với các tác vụ khác Việc tăng tốc như thế có thể đạt được chỉ nếu máy tính có nhiều thành phần đa xử lý (như các CPU hay các kênh I/O)
- Tính module hóa: chúng ta muốn xây dựng hệ thống trong một kiểu mẫu dạng module, chia các chức năng hệ thống thành những tiến trình hay luồng như đã thảo luận ở chương trước
- Tính tiện dụng: Thậm chí một người dùng đơn có thể có nhiều tác vụ thực hiện tại cùng thời điểm Thí dụ, một người dùng có thể đang soạn thảo, in, và biên dịch cùng một lúc
2.4.2 Giao tiếp giữa các tiến trình
Thực thi đồng hành của các tiến trình cộng tác yêu cầu các cơ chế cho phép các tiến trình giao tiếp với các tiến trình khác và đồng bộ hóa các hoạt động của chúng Đó chính là cơ chế giao tiếp giữa các tiến trình (Interprocess communication - IPC)
Sau đây chúng ta sẽ tìm hai mô hình giao tiếp giữa các tiến trình là chia sẻ bộ nhớ và
Trang 11truyền thông điệp
Hình 2.7 Mô hình giao tiếp giữa các tiến trình
(a) truyền thông điệp (b) chia sẻ bộ nhớ
2.4.3 Mô hình giao tiếp qua chia sẻ bộ nhớ
Để minh họa khái niệm của các quá trình cộng tác, chúng ta xem xét bài toán người sản xuất - người tiêu thụ, là mô hình chung cho các tiến trình cộng tác Tiến trình người sản xuất cung cấp thông tin được tiêu thụ bởi tiến trình người tiêu thụ Thí dụ, một chương trình in sản xuất các ký tự được tiêu thụ bởi trình điều khiển máy in Một trình biên dịch có thể sản xuất
mã hợp ngữ được tiêu thụ bởi trình hợp ngữ Sau đó, trình hợp ngữ có sản xuất module đối tượng, được tiêu thụ bởi bộ nạp
Để cho phép người sản xuất và người tiêu thụ chạy đồng hành, chúng ta phải có sẵn một vùng đệm chứa các sản phẩm có thể được điền vào bởi người sản xuất và được lấy đi bởi người tiêu thụ Người sản xuất có thể sản xuất một sản phẩm trong khi người tiêu thụ đang tiêu thụ một sản phẩm khác Người sản xuất và người tiêu thụ phải được đồng bộ để mà người tiêu thụ không cố gắng tiêu thụ một sản phẩm mà chưa được sản xuất Trong trường hợp này, người tiêu thụ phải chờ cho tới khi các sản phẩm mới được tạo ra
Nếu độ lớn vùng đệm không bị giới hạn (unbounded-buffer), người tiêu thụ có thể phải chờ các sản phẩm mới nhưng người sản xuất có thể luôn tạo ra sản phẩm mới Nhưng với vùng đệm có kích thước giới hạn (bounded-buffer), người tiêu thụ phải chờ nếu vùng đệm rỗng, và người sản xuất phải chờ nếu vùng đệm đầy
Vùng đệm có thể được cung cấp bởi hệ điều hành thông qua việc sử dụng bộ nhớ được chia sẻ Chúng ta xem xét một giải pháp chia sẻ bộ nhớ đối với vấn đề vùng đệm bị giới hạn (bounded-buffer) Tiến trình người sản xuất và người tiêu thụ chia sẻ các biến sau:
#define BUFFER_SIZE 10
typedef struct{
…
} item;
Trang 12==out
Mã cho tiến trình người sản xuất và người tiêu thụ được trình bày dưới đây Tiến trình
người sản xuất có một biến nextProduced trong đó sản phẩm mới được tạo ra và được lưu
trữ:
while (1) {
/*produce an item in nextProduced*/
while (((in + 1)%BUFFER_SIZE) ==out)
out = (out + 1) % BUFFER_SIZE;
/*consume the item in nextConsumed*/
}
2.4.3 Mô hình giao tiếp qua truyền thông điệp
Giao tiếp giữa các tiến trình thông qua việc gửi thông điệp Để hỗ trợ cơ chế liên lạc bằng thông điệp, hệ điều hành cung cấp các hàm IPC chuẩn, cơ bản là hai hàm: Send(message), gửi một thông điệp và Receive(message), nhận một thông điệp
Trang 13Send(P, message): gửi một thông điệp tới tiến trình P
Receive(Q, message): nhận một thông điệp từ tiến trình Q
Một liên kết giao tiếp trong cơ chế này có những thuộc tính sau:
- Một liên kết được thiết lập tự động giữa mỗi cặp tiến trình muốn giao tiếp
- Các tiến trình cần biết định danh của nhau khi giao tiếp
- Một liên kết được nối kết với chính xác hai tiến trình
- Chính xác một liên kết tồn tại giữa mỗi cặp tiến trình
Với giao tiếp gián tiếp, một thông điệp được gửi tới và nhận từ các hộp thư (mailboxes), hay cổng (ports) Một hộp thư có thể được hiển thị trừu tượng như một đối tượng trong đó các thông điệp có thể được đặt bởi các tiến trình và sau đó các thông điệp này có thể được xóa đi Mỗi hộp thư có một định danh duy nhất Trong cơ chế này, một tiến trình có thể giao tiếp với một vài tiến trình khác bằng một số hộp thư khác nhau Hai tiến trình có thể giao tiếp chỉ nếu chúng chia sẻ cùng một hộp thư Hàm cơ sở send và receive được định nghĩa như sau:
Send(A, message): gửi một thông điệp tới hộp thư A
Receive(A, message): nhận một thông điệp từ hộp thư A
Trong cơ chế này, một liên kết giao tiếp có các thuộc tính sau:
- Một liên kết được thiết lập giữa một cặp tiến trình chỉ nếu cả hai thành viên của cặp có một hộp thư được chia sẻ
- Một liên kết có thể được nối kết với nhiều hơn hai tiến trình
- Số các liên kết khác nhau có thể tồn tại giữa mỗi cặp tiến trình giao tiếp với mỗi liên kết tương ứng với một hộp thư
b Đồng bộ hóa
Giao tiếp giữa hai quá trình xảy ra bởi lời gọi hàm cơ sở send và receive Có các tùy chọn thiết kế khác nhau cho việc cài đặt mỗi hàm cơ sở Truyền thông điệp có thể là nghẽn (block) hay không nghẽn (nonblocking)-cũng được xem như đồng bộ và bất đồng bộ
Hàm send nghẽn: quá trình gửi bị nghẽn cho đến khi thông điệp được nhận bởi quá trình nhận hay bởi hộp thư
Hàm send không nghẽn: quá trình gửi gửi thông điệp và thực hiện tiếp hoạt động Hàm receive nghẽn: người nhận nghẽn cho đến khi thông điệp sẵn sàng
Hàm receive không nghẽn: người nhận nhận lại một thông điệp hợp lệ hay rỗng
Sự kết hợp khác nhau giữa send và receive là có thể Khi cả hai hàm send và receive là nghẽn chúng ta có sự thống nhất giữa người gửi và người nhận
c Tạo vùng đệm
Dù giao tiếp có thể là trực tiếp hay gián tiếp, các thông điệp được chuyển đổi bởi các quá trình giao tiếp thường trú trong một hàng đợt tạm thời Về cơ bản, một hàng đợi như thế có thể được cài đặt trong ba cách:
Trang 14- Khả năng chứa là 0 (zero capacity): hàng đợi có chiều dài tối đa là 0; do đó liên kết không thể có bất kỳ thông điệp nào chờ trong nó Trong trường hợp này, người gửi phải nghẽn cho tới khi người nhận nhận thông điệp
- Khả năng chứa có giới hạn (bounded capacity): hàng đợi có chiều dài giới hạn n; do
đó, nhiều nhất n thông điệp có thể thường trú trong nó Nếu hàng đợi không đầy khi một thông điệp mới được gửi, sau đó nó được đặt trong hàng đợi (thông điệp được chép hay một con trỏ thông điệp được giữ) và người gửi có thể tiếp tục thực thi không phải chờ Tuy nhiên, liên kết có khả năng chứa giới hạn Nếu một liên kết đầy, người gửi phải nghẽn cho tới khi không gian là sẳn dùng trong hàng đợi
- Khả năng chứa không giới hạn (unbounded capacity): Hàng đợi có khả năng có chiều dài không giới hạn; do đó số lượng thông điệp bất kỳ có thể chờ trong nó Người gửi không bao giờ nghẽn
2.5 Luồng (Thread)
Trong các hệ điều hành cũ, mỗi tiến trình có một không gian địa chỉ riêng và chỉ một dòng chạy chương trình (tuần tự chạy các lệnh từ lệnh đầu tiên) Tuy nhiên trong nhiều trường hợp công việc cần có nhiều dòng chạy chương trình chạy “song song” trong cùng một không gian địa chỉ
2.5.1 Khái niệm luồng
Mô hình tiến trình dựa trên hai điều: gom nhóm tài nguyên và chạy chương trình Gom nhóm tài nguyên là gom các tài nguyên có liên quan đến một công việc lại với nhau như không gian địa chỉ để nạp chương trình xử lý công việc, các tập tin được mở liên quan đến công việc … Chạy chương trình là chạy các mã để thực hiện công việc, đó là dòng chạy
chương trình Dòng chạy chương trình có bộ đếm chương trình, thanh ghi, ngăn xếp, … riêng
Trong một tiến trình có thể có nhiều dòng chạy chương trình đồng thời, mỗi dòng chạy chương trình được gọi là luồng
Các luồng của một tiến trình sẽ dùng chung môi trường của tiến trình, tức là dùng chung không gian địa chỉ, các tập tin được mở,… của tiến trình
Hình 2.8 Luồng
Tiến trình đa luồng (multithreaded process) là tiến trình có nhiều luồng
Hình (a): Có ba tiến trình, mỗi tiến trình chỉ có một dòng chạy chương trình và có
Trang 15không gian địa chỉ riêng Hình (b) có một tiến trình, trong tiến trình có ba luồng Ba luồng này
có cùng không gian địa chỉ, tài nguyên của tiến trình
Trong tiến trình đa luồng, các luồng chạy được luân phiên chạy (giống như sự luân phiên chạy của các tiến trình) Trong khi tiến trình đang chạy, CPU sẽ lần lượt phục vụ cho các luồng trong tiến trình này
Các luồng trong một tiến trình thì không hoàn toàn độc lập nhau như giữa các tiến trình Các luồng trong một tiến trình dùng chung không gian địa chỉ, nghĩa là các luồng có thể dùng chung các biến toàn cục, luồng có thể truy xuất đến bất cứ địa chỉ nào trong không gian địa chỉ của tiến trình, luồng có thể đọc, ghi lên cả ngăn xếp của luồng khác trong cùng tiến trình Không có cơ chế bảo vệ giữa các luồng vì không thể làm được, và không cần thiết vì các luồng trong một tiến trình cùng phối hợp nhau để thực hiện một công việc nào đó (trách nhiệm thuộc về người lập trình), điều này khác với tiến trình vì các tiến trình là những chương trình thực hiện các công việc khác nhau (của những người viết khác nhau)
2.5.2 Cài đặt luồng
a Cài đặt luồng mức người dùng
Có hai hướng chính cài đặt luồng: trong mức người dùng và trong kernel Khi cài đặt luồng trong mức người dùng thì kernel không biết gì về luồng, kernel chỉ biết tiến trình (có một luồng) Thuận lợi khi cài đặt luồng ở mức người dùng là luồng có thể cài đặt luồng trong những hệ điều hành không hỗ trợ luồng
Mỗi tiến trình có riêng bảng luồng để lưu trữ thông tin về các luồng trong tiến trình đó Bảng luồng tương tự như bảng tiến trình của nhân, lưu giữ bộ đếm chương trình của luồng, con trỏ ngăn xếp, thanh ghi, trạng thái luồng … Khi luồng chuyển về trạng thái sẵn sàng chạy hoặc bị treo thì các thông tin của luồng sẽ được lưu lại
Hình 2.9 Luồng ở mức người dùng
Khi một luồng thực hiện một lệnh có thể dẫn đến bị treo (như đợi một luồng khác), nó gọi thủ tục hệ thống đang chạy (run-time), thủ tục này lưu các thanh ghi vào bảng luồng và bắt đầu cho luồng khác chạy Trong tiến trình có một hệ thống đang chạy (run-time system)
Trang 16Khi một luồng ngưng chạy như gọi hàm luồng_yeild, hàm này sẽ lưu các thông tin của
luồng vào trong bảng luồng, sau đó gọi bộ lập lịch luồng để cho luồng khác chạy Vì bộ lập lịch luồng là thủ tục cục bộ, không phải gọi hàm hệ thống nên thực hiện nhanh Mỗi tiến trình
có thể có giải thuật lập lịch luồng riêng
Tuy nhiên cài đặt luồng trong mức người dùng có những điểm hạn chế sau:
Cài đặt các hàm gọi hệ thống blocking (blocking system call) ? Khi một luồng thực hiện gọi hệ thống (blocking) thì tất cả các luồng trong tiến trình đều bị ngưng Điều này dẫn đến phải có các hàm gọi hệ thống không blocking (nonblocking system call), và làm ảnh hưởng rất nhiều đến các chương trình khác
Khi một luồng chạy thì các luồng trong tiến trình đó không có cơ hội để chạy trừ khi luồng đang chạy tự nguyện nhường CPU vì trong một tiến trình không có ngắt thời gian nên
bộ lập lịch luồng không thể chạy được
b Cài đặt luồng ở mức nhân
Trong tiến trình không có bảng luồng, kernel sẽ có bảng luồng lưu giữ thông tin của tất
cả các luồng trong hệ thống Khi một luồng được tạo hay hủy bỏ thì gọi hàm hệ thống, do vậy thời gian thực hiện chậm
Khi một luồng thực hiện gọi hệ thống, trong trường hợp blocking thì luồng này sẽ bị treo, và kernel sẽ cho luồng khác trong cùng tiến trình chạy nếu có, hoặc luồng của tiến trình khác chạy Do vậy các luồng không cần thiết phải có những hàm gọi thống không blocking
Trang 17Hệ điều hành phải có cơ chế cung cấp được nhiều luồng ở mức nhân cho một tiến trình
Mô hình many-to-many
Hình 2.11 Mô hình many-to-many
Trang 18Nhiều ở mức người dùng được phân chia thực thi (multiplexed) trên một số luồng ở mức nhân
Tránh được một số khuyết điểm của hai mô hình many-to-one và one-to-one
CÂU HỎI ÔN TẬP
1 Phân biệt chương trình với tiến trình
2 Nêu các trạng thái của tiến trình
3 Xác định các thành phần chính của khối điều kiển tiến trình
4 Tại sao phải giao tiếp giữa các tiến trình Nêu các cơ chế giao tiếp giữa các tiến trình
5 Trình bày các mô hình luồng
TÀI LIỆU THAM KHẢO
1 Hồ Đắc Phương Giáo trình nguyên lý hệ điều hành Nhà xuất bản Giáo dục, 2009
Chương 4
2 A.Silberschatz, P B Galvin, G Gagne Operating System Concepts, 8th Edition
John Wiley & Sons, 2009 Chương 3,4
3 William Stallings Operating Systems: Internals and Design Principles (6th
Edition) Pearson Prentice Hall, 2009 Chương 3,4
Trang 19CHƯƠNG 3 LẬP LỊCH CPU 3.1 Các khái niệm cơ bản
3.1.1 Chu kỳ CPU-I/O
Sự thành công của việc lập lịch CPU phụ thuộc vào thuộc tính được xem xét sau đây của quá trình Việc thực thi quá trình chứa một chu kỳ (cycle) thực thi CPU và chờ đợi vào/ra Các quá trình chuyển đổi giữa hai trạng thái này Sự thực thi quá trình bắt đầu với một chu kỳ CPU (CPU burst), theo sau bởi một chu kỳ vào/ra (I/O burst), sau đó một chu kỳ CPU khác, sau đó lại tới một chu kỳ vào/ra khác khác, Sau cùng, chu kỳ CPU cuối cùng sẽ kết thúc với một yêu cầu hệ thống để kết thúc việc thực thi, hơn là với một chu kỳ vào/ra khác, được mô tả như hình 3.1 Một chương trình hướng vào/ra (I/O-bound) thường có nhiều chu kỳ CPU ngắn Một chương trình hướng xử lý (CPU-bound) có thể có một nhiều chu kỳ CPU dài Sự phân bổ này có thể giúp chúng ta chọn giải thuật lập lịch CPU hợp lý
Hình 3.1 Sơ đồ thực hiện tiến trình
3.1.2 Phân loại các hoạt động lập lịch
Lập lịch dài hạn (long-term scheduling): xác định tiến trình nào được chấp nhận vào hệ
Trang 20thống Quyết định độ-đa-lập-trình (degree of multiprogramming) Nếu càng nhiều tiến trình
được đưa vào hệ thống thì: khả năng các process bị block có xu hướng giảm; sử dụng CPU hiệu quả hơn; mỗi process được phân chia khoảng thời gian sử dụng CPU thấp hơn
Thường có xu hướng đưa vào một tập lẫn lộn các tiến trình CPU-bound và tiến trình I/O-bound
Hình 3.2 Các hoạt động lập lịch
Lập lịch trung hạn (medium-term scheduling): xác định process nào được đưa vào
(swap in), đưa ra khỏi (swap out) bộ nhớ chính Phụ thuộc vào yêu cầu quản lý việc trình (multiprogramming) Cho phép bộ lập lịch dài hạn chấp nhận nhiều process hơn số lượng process mà có tổng kích thước được chứa vừa trong bộ nhớ chính Nhưng nếu có quá nhiều process thì sẽ làm tăng việc truy xuất đĩa, do đó cần phải lựa chọn độ-đa-lập-trình cho phù hợp Được thực hiện bởi phần mềm quản lý bộ nhớ
đa-lập-Lập lịch ngắn hạn (short-term scheduling): xác định process nào được thực thi tiếp theo
nên còn được gọi là lập lịch CPU Được kích hoạt khi có một sự kiện có thể dẫn đến khả năng chọn một process để thực thi:ngắt thời gian, ngắt ngoại vi, lời gọi hệ thống…
3.1.3 Hai thành phần của chiến lược lập lịch
a Hàm lựa chọn (selection function)
Xác định process nào trong ready queue sẽ được thực thi tiếp theo Thường theo các tiêu chí như: tổng thời gian đợi trong hệ thống, thời gian đã được phục vụ, tổng thời gian thực thi của tiến trình
b Chế độ quyết định (decision mode)
Chọn thời điểm hàm lựa chọn lập lịch thực thi Có hai chế độ:
- Nonpreemptive (độc quyền): Một tiến trình sẽ ở trạng thái running cho đến khi nó bị block hoặc nó kết thúc
- Preemptive (không độc quyền): tiến trình đang thực thi có thể bị ngắt và chuyển về
Trang 21trạng thái sẵn sàng nhằm tránh trường hợp một tiến trình độc chiếm CPU
Hàm lập lịch có thể được thực thi khi có tiến trình:
(1) chuyển từ trạng thái đang thực thi sang chờ
(2) chuyển từ trạng thái đang thực thi sang sẵn sàng
(3) chuyển từ trạng thái chờ, mới sang sẵn sàng
(4) kết thúc thực thi
Lập lịch nonpreemptive: chỉ thực thi hàm lập lịch trong trường hợp 1 và 4
Lập lịch preemptive: ngoài trường hợp 1 và 4 còn thực thi thêm hàm lập lịch trong
trường hợp 2 hoặc 3 (hoặc cả hai)
3.1.4 Bộ điều phối (dispatcher)
Bộ điều phối sẽ chuyển quyền điều khiển CPU về cho tiến trình được chọn bởi bộ lập lịch ngắn hạn Chức năng này thực hiện:
- Chuyển ngữ cảnh (sử dụng thông tin ngữ cảnh trong PCB)
Thời gian hoàn thành (turnaround time): Thời gian để một tiến trình hoàn tất, kể từ lúc vào hệ thống đến lúc kết thúc Thời gian hoàn thành là tổng các thời gian chờ đưa tiến trình vào bộ nhớ, chờ hàng đợi sẳn sàng, thực thi CPU và thực hiện vào/ra
Thời gian chờ (waiting time): là tổng thời gian tiến trình chờ trong hàng đợi sẵn sàng Thời gian đáp ứng (response time): Thời gian từ lúc có yêu cầu của người dùng đến khi
có đáp ứng đầu tiên
3.2.2 Mục tiêu điều phối:
Bộ điều phối tiến trình của hệ điều hành phải đạt được các mục tiêu sau đây trong công
tác điều phối:
Trang 22Sự công bằng (Fairness): Các tiến trình đều công bằng với nhau trong việc chia sẻ thời gian xử lý của CPU, không có tiến trình nào phải chờ đợi vô hạn để được cấp CPU
Tính hiệu quả: Tận dụng được 100% thời gian xử lý của CPU Trong công tác điều phối, khi CPU rỗi bộ điều phối sẽ chuyển ngay nó cho tiến trình khác, nếu trong hệ thống có tiến trình đang ở trạng thái chờ CPU, nên mục tiêu này dễ đạt được Tuy nhiên, nếu hệ điều hành đưa vào hệ thống quá nhiều tiến trình thiên hướng vào/ra, thì nguy cơ CPU bị rỗi là có thể Do đó, để đạt được mục tiêu này hệ điều hành phải tính toán và quyết định nên đưa vào
hệ thống bao nhiêu tiến trình hướng vào/ra, bao nhiêu tiến trình hướng xử lý, là thích hợp Thời gian đáp ứng hợp lý: Một tiến trình đáp ứng yêu cầu của người sử dụng, phải nhận được thông tin hồi đáp từ yêu cầu của nó thì nó mới có thể trả lời người sử dụng Do đó, theo người sử dụng thì bộ phận điều phối phải cực tiểu hoá thời gian đáp ứng của các tiến trình, có như vậy thì tính tương tác của tiến trình mới tăng lên
Thời gian lưu lại trong hệ thống: Phải cực tiểu thời gian hoàn thành nhất là các tác vụ
xử lý theo lô
Thông lượng tối đa: Chính sách điều phối phải cố gắng để cực đại được số lượng tiến trình hoàn thành trên một đơn vị thời gian Mục tiêu này ít phụ thuộc vào chính sách điều phối
mà phụ thuộc nhiều vào thời gian thực hiện trung bình của các tiến trình
Công tác điều phối của hệ điều hành khó có thể thỏa mãn đồng thời tất cả các mục tiêu trên vì bản thân các mục tiêu này đã có sự mâu thuẫn với nhau Các hệ điều hành chỉ có thể dung hòa các mục tiêu này ở một mức độ nào đó
3.3 Các thuật toán lập lịch
3.3.1 Đến trước phục vụ trước (First Come Pirst Served - FCFS)
Trong thuật toàn này, độ ưu tiên phục vụ tiến trình căn cứ vào thời điểm hình thành tiến trình Việc cài đặt thuật toán FCFS được quản lý dễ dàng với hàng đợi FIFO Khi CPU rỗi thì
hệ điều hành sẽ cấp nó cho tiến trình đầu tiên trong hàng đợi sẵn sàng, đây là tiến trình được chuyển sang trạng thái sẵn sàng sớm nhất, có thể là tiến trình được đưa vào hệ thống sớm nhất FIFO được sử dụng trong điều phối độc quyền nên khi tiến trình được cấp CPU nó sẽ sở hữu CPU cho đến khi kết thúc xử lý hay phải đợi một thao tác vào/ra hoàn thành, khi đó tiến trình chủ động trả lại CPU cho hệ thống
Ví dụ: cho các tiến trình sau đến ở thời điểm 0 theo thứ tự P1 , P2 , P3 có thời gian xử lý như sau:
Tiến trình Thời gian xử lý (ms)
Trang 23Thời gian đợi cho P1 = 0, P2 = 24, P3 = 27
Thời gian đợi trung bình: (0 + 24 + 27)/3 = 17
Nếu các tiến trình đến theo thứ tự: P2 , P3 , P1 thì giản đồ Gantt cho việc lập lịch là:
Thời gian đợi cho P1 = 6, P2 = 0, P 3 = 3 Thời gian đợi trung bình là: (6 + 0 + 3)/3 = 3
Tốt hơn rất nhiều so với trường hợp trước
Ưu điểm của thuật toán này là thời gian CPU không bị phân phối lại (không bị ngắt) và chi phí tổ chức thực hiện thấp nhất (vì khỏng phải thay đồỉ thứ tự ưu tiên phục vụ, thứ tự trư tiên là thứ tự của tiến trình trong hàng đợi)
Nhược điểm của thuật toán là thời gian trung bình chờ phục vụ của các tiến trình là như nhau không kể tiến trình ngắn hay đài), do đó dẫn tới ba nhược điểm sau:
- Thời gian chờ đời trung bình sẽ tăng vô hạn khi hệ thống tiếp cận tới hạn khả năng phục vụ của mình
- Nếu độ phát tán thời gian thực hiện tiến trình tăng thì thời gian chờ đợi trung bình cũng tăng theo
- Khi có tiến trình dài, ít bị ngắt thì các tiến trình khác phải chờ đợi lâu hơn
3.3.2 Công việc ngắn nhất trước (Shortest Job First - SJF)
Thuật toán SJF xác định thứ tự ưu tiên thực hiện tiến trình tựa vào tổng thời gian thực hiện tiến trình Tiến trình nào có tổng thời gian thực hiện ngắn sẽ được ưu tiên phục vụ trước
Ví dụ: cho dãy tiến trình có thời điểm đến và thời gian xử lý như sau:
Tiến trình Thời điểm đến Thời gian xử lý(ms)
Giản đồ Gantt khi lập lịch theo SJF là:
Thời gian đợi trung bình = (0 + 6 + 3 + 7)/4 = 4
Ưu điểm của thuật toán là thời gian chờ đợi trung bình của các tiến trình ngắn hơn so với FCFS SJF nhanh chóng loại bỏ các tiến trình ngắn giảm số lượng các tiến trình trong hàng đợi
Nhược điểm chính của thuật toán là chế độ phân phối lại thời gian CPU cũng được áp
Trang 24dụng trong trường hợp ngắt các tiến trình dài đang thực hiện để phục vụ các tiến trình ngắn hơn mới mất hiện trong hàng đợi Nếu tiến trình mới xuất hiện có tổng thời gian thực hiện ngắn nhưng vẫn lớn hơn thời gian cần thiết để thực hiện nốt tiến trình đang thực hiện thì việc ngắt tiến trình là không hợp lý
Khó khăn thật sự với thuật toán SJF là làm thế nào để biết chiều dài của yêu cầu CPU tiếp theo Một kỹ thuật thường dùng để dự đoán thời gian sử dụng CPU là dùng trung bình hàm mũ (exponential averaging) Chu kỳ CPU kế tiếp thường được đoán như trung bình số
mũ của chiều dài các chu kỳ CPU trước đó Gọi tn là chiều dài của chu kỳ CPU thứ n và gọi τn+1 giá trị được đoán cho chu kỳ CPU kế tiếp Thì đối với α, với 0 ≤ α ≤ 1, định nghĩa: τn+1 = α tn + (1 - α) τn
Thay thế ta có:
τn+1 = αtn + (1- α) α tn-1 +…+ (1- α)jαtn-j +…+ (1- α)n+1 ατ0
Nếu chọn α = ½ thì có nghĩa là trị đo được tn và trị dự đoán τn được xem quan trọng như nhau
Hình 3.3 dự đoán thời gian sử dụng CPU
3.3.3 Công việc còn lại ngắn nhất trước (Shortest Remaining Time First - SRTF)
Tương tự như SJF nhưng trong thuật toán này, độ ưu tiên thực hiện các tiến trình dựa vào thời gian cần thiết để thực hiện nốt tiền trình (bằng tổng thời gian trừ đi thời gian đã thực hiện) Như vậy, trong thuật toàn này cần phải thường xuyên cặp nhật thông tin về thời gian đã thực hiện tiến trình Đồng thời, chế độ phân bố lại thời CPU cũng phải được áp dụng nếu không sẽ làm mất tính tưu việt của thuật toán Đây có thể coi là phiên bản của SJF theo chế độ không độc quyền
Ví dụ: cho dãy tiến trình có thời điểm đến và thời gian phục vụ như sau:
Tiến trình Thời điểm đến Thời gian xử lý(ms)
Trang 25P4 5.0 4 Giản đồ Gantt khi lập lịch theo SRTF là:
Thời gian đợi trung bình = (9 + 1 + 0 + 2)/4 = 3 Tốt hơn giải thuật SJF
3.3.4 Lập lịch xoay vòng (Round Robin - RR)
Trong thuật toán này, hệ thống quy định một lượng tử thời gian (time quantum) khoảng
từ 10 - 100 mili giây
Mỗi tiến trình trong hàng đợi lần lượt được phân phối một lượng tử thời gian để thực hiện Sau khoảng thời gian đó, nếu tiến trình chưa kết thúc hoặc không rơi vào trạng thái đợi thì nó được chuyển về cuối hàng đợi
Hàng đợi các tiến trình được tổ chức theo kiểu vòng tròn và các tiến trình luôn luôn đảm bảo được phục vụ Khi có tiến trình mới phát sinh, nó sẽ được đưa vào hàng đợi vòng tròn Các tiến trình dù ngắn hay dài đều có độ ưu tiên phục vụ như nhau
Nhược điềm là do phải thường xuyên phân phối lại CPU nên thời gian chờ đợi trung bình của RR có thể lớn hơn so với FCFS
Chú ý: Trong thuật toán, cần chọn giá trị lượng tử thời gian thích hợp Nếu chọn giá trị
lượng tử thời gian lớn thì việc bố sung tiến trình mới hoặc kích hoạt tiến trình bị ngắt sẽ làm tăng thời gian chờ đợi trung bình, nhưng ngược lại nếu chọn giá trị lượng tử thời gian nhỏ thì
nó sẽ làm cho các tiến trình phải liên tục chuyển trạng thái đầu đến giảm hệ số hữu ích của CPU
Thông thường giá trị lượng tử thời gian được chọn theo công thức q = t/n hoặc q = t/n -
s Trong đó t là thời gian khống chế trước; n là số tiến trình; s là thời gian chuyển từ tiến trình này sang tiến trình khác (chuyển ngữ cảnh)
Ví dụ: cho dãy tiến trình có thời điểm đến và thời gian xử lý như sau:
Tiến trình Thời gian xử lý(ms)
Với lượng tử thời gian q = 20 ms
Giản đồ Gantt theo thuật toán RR là:
Ta có thể thấy thuật toán RR thường có thời gian quay vòng cao hơn SJF, nhưng lại có
Trang 26thời gian đáp ứng tốt hơn
3.3.5 Lập lịch ưu tiên (Priority Scheduling)
Mỗi tiến trình sẽ được gán một độ ưu tiên CPU sẽ được cấp cho tiến trình có độ ưu tiên
cao nhất SJF là một thuật lập lịch sử dụng độ ưu tiên với độ ưu tiên là thời gian sử dụng CPU
dự đoán
Lập lịch sử dụng độ ưu tiên có thể theo chế dộ đọc quyền hoặc không độc quyền
Độ ưu tiên có thể được định nghĩa bên trong hay bên ngoài Độ ưu tiên được định nghĩa bên trong thường dùng một hoặc nhiều định lượng có thể đo được để tính toán độ ưu tiên của một tiến trình Thí dụ, các giới hạn thời gian, các yêu cầu bộ nhớ, số lượng tập tin đang mở và
tỉ lệ của chu kỳ vào/ra trung bình với tỉ lệ của chu kỳ CPU trung bình Các độ ưu tiên bên ngoài được thiết lập bởi các tiêu chuẩn bên ngoài đối với hệ điều hành như sự quan trọng của tiến trình, loại và lượng chi phí đang được trả cho việc dùng máy tính, văn phòng hỗ trợ công việc,…
Vấn đề chính của lập lịch ưu tiên là trì hoãn vô hạn định (indefinite blocking) hay bị bỏ đói (starvation) – tiến trình có độ ưu tiên thấp có thể không bao giờ được thực thi Một giải pháp cho vấn đề này là sự hóa già (aging) – độ ưu tiên của tiến trình sẽ tăng theo thời gian
3.3.6 Lập lịch với hàng đợi nhiều mức (Multilevel Queue Scheduling)
Trường hợp này các tiến trình có thể được phân thành nhóm Ví dụ: các tiến trình tương tác và các tiến trình theo lô
Hàng đợi sẵn sàng sẽ được chia thành nhiều hàng đợi riêng rẽ Ví dụ: hàng đợi nền (background) cho các tiến trình theo lô, hàng đợi giao tiếp (foreground) cho các tiến trình tương tác Mỗi hàng đợi sẽ có giải thuật lập lịch riêng
Ngoài ra, cần phải lập lịch giữa các hàng đợi với nhau Việc này có thể thực hiện theo hai cách sau:
Ưu tiên cố định (fixed priority scheduling) – ví dụ: phục vụ tất cả các tiến trình của foreground rồi mới đến background Có khả năng xảy ra trì hoãn vô hạn định
Chia thời gian (time slice) – mỗi hàng đợi sẽ được lấy một khoảng sử dụng CPU nhất định để lập lịch cho các process của mình - ví dụ: 80% cho foreground (dùng RR), 20% cho background (dùng FCFS)
3.3.6 Hàng đợi phản hồi nhiều mức (Multilevel Feedback Queue)
Trang 27Hình 3.4 Hàng đợi phản hồi nhiều mức
Đây là thuật toán tổng quảt nhất để lặp lịch cho CPU Trong thuật toán này, hệ thống tổ chức nhiều hàng đợi Mổi hàng đợi có độ ưu tiên và cách thức tổ chức thực hiện khác nhau Các tiến trình có thể chuyển đổi từ hàng đợi này sang hàng đợi khác Ví dụ: Nếu một tiến trình sử dụng CPU quá lâu, nó sẽ bị di chuyển sang một hàng đợi có độ ưu tiên thấp hơn Nếu một tiến trình chờ quá lâu trong một hàng đợi có độ ưu tiên thấp, nó sẽ được di chuyển lên hàng đợi có độ ưu tiên cao hơn
Xét trường hợp sau: Có 3 hàng đợi: Q0 , dùng RR với quantum 8 ms Q1, dùng RR với quantum 16 ms, Q2 dùng FCFS
Tiến trình mới sẽ vào hàng đợi Q0 Khi đến lượt mình, tiến trình sẽ được một khoảng thời gian là 8 milli giây Nếu không kết thúc được trong 8 milli giây, tiến trình sẽ được đưa xuống hàng đợi Q1
Tại Q1, tương tự tiến trình sau khi chờ sẽ được cho một khoảng thời gian thực thi là 16 milli giây Nếu hết thời gian này vẫn chưa kết thúc sẽ bị chuyển sang Q2
Các yêu tố cần chú ý:
- Số lượng hàng đợi sao cho hợp lý
- Chọn thuật toán thích hợp cho mỗi hàng đợi
- Tiêu chuẩn và cách thức hạ mức một tiến trình
- Tiêu chuẩn và cách thức nâng mức một tiến trình
- Tiêu chuẩn và cách thức để chỉ định một tiến trình mới phát sinh đi vào hàng đợi nào
3.4 Lập lịch trên hệ thống nhiều CPU
Phần trên thảo luận chúng ta tập trung vào những vấn đề lập lịch CPU trong một hệ thống với một bộ vi xử lý đơn Nếu có nhiều CPU, vấn đề lập lịch tương ứng sẽ phức tạp hơn Nhiều khả năng đã được thử nghiệm và như chúng ta đã thấy với lập lịch CPU đơn bộ xử lý, không có giải pháp tốt nhất Trong phần sau đây, chúng ta sẽ thảo luận vắn tắt một số vấn đề tập trung về lập lịch đa bộ xử lý Chúng ta tập trung vào những hệ thống mà các bộ xử lý của
nó được xác định (hay đồng nhất) trong thuật ngữ chức năng của chúng; bất cứ bộ xử lý nào sẳn có thì có thể được dùng để chạy bất cứ tiến trình nào trong hàng đợi Chúng ta cũng cho rằng truy xuất bộ nhớ là đồng nhất (uniform memory access-UMA) Chỉ những chương trình