Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Giới thiệu về hệ điều hành

Này Habr! Theo quan điểm của tôi, tôi muốn giới thiệu với các bạn một loạt bài viết-bản dịch của một nền văn học thú vị - OSTEP. Tài liệu này thảo luận khá sâu về công việc của các hệ điều hành giống unix, cụ thể là làm việc với các tiến trình, các bộ lập lịch khác nhau, bộ nhớ và các thành phần tương tự khác tạo nên một hệ điều hành hiện đại. Bạn có thể xem bản gốc của tất cả các tài liệu ở đây đây. Xin lưu ý rằng bản dịch được thực hiện không chuyên nghiệp (khá tự do), nhưng tôi hy vọng tôi vẫn giữ được ý nghĩa chung.

Phòng thí nghiệm về chủ đề này có thể được tìm thấy ở đây:

Những khu vực khác:

Bạn cũng có thể xem kênh của tôi tại điện tín =)

Hãy xem xét sự trừu tượng cơ bản nhất mà HĐH cung cấp cho người dùng: quy trình. Định nghĩa của quá trình này khá đơn giản - đó là chương trình đang chạy. Bản thân chương trình là một thứ vô hồn nằm trên đĩa - nó là một tập hợp các hướng dẫn và có thể một số dữ liệu tĩnh đang chờ được khởi chạy. Hệ điều hành sẽ lấy những byte đó và chạy chúng, biến chương trình thành thứ gì đó hữu ích.
Thông thường, người dùng muốn chạy nhiều chương trình cùng lúc, chẳng hạn như bạn có thể chạy trình duyệt, trò chơi, trình phát đa phương tiện, trình soạn thảo văn bản, v.v. trên máy tính xách tay của mình. Trên thực tế, một hệ thống điển hình có thể chạy hàng chục hoặc hàng trăm quy trình cùng một lúc. Thực tế này làm cho hệ thống dễ sử dụng hơn, bạn không bao giờ phải lo lắng về việc CPU có rảnh hay không mà chỉ cần chạy chương trình.

Điều này đặt ra vấn đề: làm thế nào để tạo ra ảo giác về nhiều CPU? Làm thế nào hệ điều hành có thể tạo ra ảo tưởng về số lượng CPU gần như vô hạn, ngay cả khi bạn chỉ có một CPU vật lý?

HĐH tạo ra ảo ảnh này thông qua ảo hóa CPU. Bằng cách bắt đầu một quá trình, sau đó dừng nó, bắt đầu một quá trình khác, v.v., HĐH có thể duy trì ảo tưởng rằng có nhiều CPU ảo, trong khi thực tế sẽ có một hoặc nhiều bộ xử lý vật lý. Kỹ thuật này được gọi là phân chia tài nguyên CPU theo thời gian. Kỹ thuật này cho phép người dùng chạy bao nhiêu tiến trình đồng thời tùy thích. Cái giá của giải pháp này là hiệu năng - vì nếu CPU được chia sẻ bởi nhiều tiến trình thì mỗi tiến trình sẽ được xử lý chậm hơn.
Để thực hiện ảo hóa CPU và đặc biệt là làm tốt điều đó, HĐH cần hỗ trợ cả cấp độ thấp và cấp độ cao. Hỗ trợ cấp thấp được gọi là cơ chế là các phương thức hoặc giao thức cấp thấp thực hiện phần chức năng được yêu cầu. Một ví dụ về chức năng như vậy là chuyển đổi ngữ cảnh, giúp hệ điều hành có khả năng dừng một chương trình và chạy một chương trình khác trên bộ xử lý. Việc phân chia thời gian này được thực hiện trong tất cả các hệ điều hành hiện đại.
Ngoài các cơ chế này còn có một số logic được tích hợp trong HĐH, dưới dạng “chính sách”. Chính sách là một thuật toán ra quyết định nhất định cho hệ điều hành. Ví dụ: các chính sách như vậy sẽ quyết định chương trình nào sẽ được khởi chạy (từ danh sách lệnh) trước tiên. Vì vậy, ví dụ, vấn đề này sẽ được giải quyết bằng một chính sách có tên lập lịch (chính sách lập lịch) và khi chọn giải pháp, nó sẽ được hướng dẫn bởi các dữ liệu như: lịch sử khởi động (chương trình nào được khởi chạy lâu nhất trong những phút cuối), quá trình này mang tải gì (loại chương trình nào đã được khởi chạy), số liệu hiệu suất (liệu hệ thống có được tối ưu hóa cho tương tác tương tác hoặc cho thông lượng), v.v.

Trừu tượng hóa: quá trình

Sự trừu tượng hóa của một chương trình đang chạy được thực thi bởi hệ điều hành được gọi là quá trình. Như đã đề cập trước đó, một tiến trình chỉ đơn giản là một chương trình đang chạy, tại bất kỳ khoảng thời gian tức thời nào. Một chương trình mà chúng tôi có thể lấy thông tin tóm tắt từ nhiều tài nguyên hệ thống khác nhau mà chương trình này truy cập hoặc ảnh hưởng trong quá trình thực thi.
Để hiểu các thành phần của quy trình, bạn cần hiểu các trạng thái của hệ thống: chương trình có thể đọc hoặc thay đổi những gì trong quá trình hoạt động. Tại bất kỳ thời điểm nào, bạn cần hiểu yếu tố nào của hệ thống là quan trọng đối với việc thực hiện chương trình.
Một trong những yếu tố hiển nhiên của trạng thái hệ thống mà quy trình bao gồm là память. Hướng dẫn được đặt trong bộ nhớ. Dữ liệu mà chương trình đọc hoặc ghi cũng nằm trong bộ nhớ. Vì vậy, bộ nhớ mà một tiến trình có thể đánh địa chỉ (được gọi là không gian địa chỉ) là một phần của tiến trình.
Ngoài ra một phần của trạng thái hệ thống là các thanh ghi. Nhiều lệnh nhằm mục đích thay đổi giá trị của các thanh ghi hoặc đọc giá trị của chúng, và do đó các thanh ghi cũng trở thành một phần quan trọng trong hoạt động của quy trình.
Cần lưu ý rằng trạng thái máy cũng được hình thành từ một số thanh ghi đặc biệt. Ví dụ, IP - con trỏ lệnh - một con trỏ tới lệnh mà chương trình hiện đang thực hiện. Ngoài ra còn có con trỏ ngăn xếp và liên quan đến nó con trỏ khung, được sử dụng để quản lý: tham số hàm, biến cục bộ và địa chỉ trả về.
Cuối cùng, các chương trình thường truy cập vào ROM (bộ nhớ chỉ đọc). Thông tin “I/O” (đầu vào/đầu ra) này phải bao gồm danh sách các tệp hiện đang được quy trình mở.

API quy trình

Để nâng cao hiểu biết của chúng ta về cách thức hoạt động của quy trình, chúng ta hãy nghiên cứu các ví dụ về lệnh gọi hệ thống nên có trong bất kỳ giao diện hệ điều hành nào. Các API này có sẵn ở dạng này hay dạng khác trên bất kỳ HĐH nào.

Tạo (tạo): Hệ điều hành phải bao gồm một số phương pháp cho phép bạn tạo các quy trình mới. Khi bạn nhập lệnh vào thiết bị đầu cuối hoặc khởi chạy một ứng dụng bằng cách nhấp đúp vào biểu tượng, một cuộc gọi sẽ được gửi đến HĐH để tạo một quy trình mới và sau đó khởi chạy chương trình đã chỉ định.
Xóa: Vì có giao diện để tạo một quy trình nên hệ điều hành cũng phải cung cấp khả năng buộc xóa một quy trình. Hầu hết các chương trình sẽ tự khởi động và kết thúc khi chạy. Nếu không, người dùng muốn có thể tiêu diệt chúng và do đó, một giao diện để dừng quá trình sẽ hữu ích.
Đợi (đang chờ): Đôi khi việc đợi một quá trình hoàn tất là rất hữu ích, do đó một số giao diện được cung cấp để cung cấp khả năng chờ.
Kiểm soát linh tinh (các loại điều khiển): Ngoài việc tiêu diệt và chờ đợi quá trình, còn có các phương pháp điều khiển khác nhau. Ví dụ: hầu hết các hệ điều hành đều cung cấp khả năng đóng băng một tiến trình (dừng quá trình thực thi của nó trong một khoảng thời gian nhất định) và sau đó tiếp tục lại (tiếp tục thực thi)
Trạng thái (trạng thái): Có nhiều giao diện khác nhau để lấy một số thông tin về trạng thái của một quy trình, chẳng hạn như nó đã chạy được bao lâu hoặc nó hiện đang ở trạng thái nào.

Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Tạo quy trình: Chi tiết

Một trong những điều thú vị là các chương trình được chuyển đổi thành các quy trình một cách chính xác như thế nào. Đặc biệt là cách hệ điều hành tiếp nhận và chạy chương trình. Làm thế nào chính xác quá trình được tạo ra.
Trước hết, HĐH phải tải mã chương trình và dữ liệu tĩnh vào bộ nhớ (vào không gian địa chỉ tiến trình). Các chương trình thường được đặt trên đĩa hoặc ổ cứng thể rắn ở một số định dạng thực thi được. Do đó, quá trình tải chương trình và dữ liệu tĩnh vào bộ nhớ yêu cầu HĐH phải có khả năng đọc các byte đó từ đĩa và đặt chúng ở đâu đó trong bộ nhớ.

Trong các hệ điều hành đầu tiên, quá trình tải được thực hiện một cách nhanh chóng, có nghĩa là toàn bộ mã đã được tải vào bộ nhớ trước khi chương trình được khởi chạy. Các hệ điều hành hiện đại thực hiện việc này một cách lười biếng, nghĩa là chỉ tải các đoạn mã hoặc dữ liệu khi chương trình yêu cầu chúng trong quá trình thực thi.

Sau khi mã và dữ liệu tĩnh được tải vào bộ nhớ hệ điều hành, có một số việc nữa cần được thực hiện trước khi quy trình có thể chạy. Một số lượng bộ nhớ phải được phân bổ cho ngăn xếp. Các chương trình sử dụng ngăn xếp cho các biến cục bộ, tham số hàm và địa chỉ trả về. HĐH phân bổ bộ nhớ này và cung cấp nó cho tiến trình. Ngăn xếp cũng có thể được phân bổ với một số đối số, cụ thể là nó điền vào các tham số của hàm main(), ví dụ như với một mảng argc và argv.

Hệ điều hành cũng có thể cấp phát một số bộ nhớ cho vùng nhớ chương trình. Heap được các chương trình sử dụng để yêu cầu rõ ràng dữ liệu được phân bổ động. Các chương trình yêu cầu không gian này bằng cách gọi hàm malloc () và xóa nó một cách rõ ràng bằng cách gọi hàm miễn phí(). Heap cần thiết cho các cấu trúc dữ liệu như bảng liên kết, bảng băm, cây và các cấu trúc khác. Lúc đầu, một lượng nhỏ bộ nhớ được phân bổ cho vùng heap, nhưng theo thời gian, khi chương trình chạy, vùng heap có thể yêu cầu thêm bộ nhớ thông qua lệnh gọi API thư viện malloc(). Hệ điều hành tham gia vào quá trình phân bổ nhiều bộ nhớ hơn để giúp đáp ứng các lệnh gọi này.

Hệ điều hành cũng sẽ thực hiện các tác vụ khởi tạo, đặc biệt là các tác vụ liên quan đến I/O. Ví dụ: trên hệ thống UNIX, mỗi quy trình theo mặc định có 3 bộ mô tả tệp đang mở cho đầu vào, đầu ra và lỗi tiêu chuẩn. Những tay cầm này cho phép các chương trình đọc đầu vào từ thiết bị đầu cuối cũng như hiển thị thông tin trên màn hình.

Do đó, bằng cách tải mã và dữ liệu tĩnh vào bộ nhớ, tạo và khởi tạo ngăn xếp cũng như thực hiện các công việc khác liên quan đến thực hiện các tác vụ I/O, HĐH sẽ chuẩn bị giai đoạn cho quy trình thực thi. Cuối cùng, còn một nhiệm vụ cuối cùng: chạy chương trình thông qua điểm vào của nó, được gọi là hàm main(). Bằng cách thực thi hàm main(), HĐH chuyển quyền điều khiển CPU sang tiến trình mới được tạo, do đó chương trình bắt đầu thực thi.

Trạng thái tiến trình

Bây giờ chúng ta đã hiểu một số quy trình là gì và nó được tạo ra như thế nào, hãy liệt kê các trạng thái của quy trình mà nó có thể có. Ở dạng đơn giản nhất, một tiến trình có thể ở một trong các trạng thái sau:
Chạy. Khi chạy, tiến trình chạy trên bộ xử lý. Điều này có nghĩa là các hướng dẫn đang được thực thi.
Sẵn sàng. Ở trạng thái sẵn sàng, tiến trình đã sẵn sàng để chạy, nhưng vì lý do nào đó mà hệ điều hành không thực thi nó vào thời gian đã chỉ định.
Bị chặn. Ở trạng thái bị chặn, một tiến trình thực hiện một số thao tác khiến nó không thể sẵn sàng thực thi cho đến khi một sự kiện nào đó xảy ra. Một ví dụ phổ biến là khi một tiến trình bắt đầu thao tác IO, nó sẽ bị chặn để một số tiến trình khác có thể sử dụng bộ xử lý.

Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Bạn có thể tưởng tượng những trạng thái này dưới dạng biểu đồ. Như chúng ta có thể thấy trong hình, trạng thái của quy trình có thể thay đổi giữa CHẠY và SẴN SÀNG theo quyết định của HĐH. Khi trạng thái của một tiến trình thay đổi từ SẴN SÀNG sang CHẠY, điều đó có nghĩa là tiến trình đó đã được lên lịch. Theo hướng ngược lại - bị xóa khỏi bố cục. Tại thời điểm một tiến trình bị BLOCKED, chẳng hạn như tôi bắt đầu một thao tác IO, hệ điều hành sẽ giữ nó ở trạng thái này cho đến khi một số sự kiện xảy ra, chẳng hạn như việc hoàn thành IO. tại thời điểm này, quá trình chuyển đổi sang trạng thái SẴN SÀNG và có thể ngay lập tức sang trạng thái CHẠY nếu HĐH quyết định như vậy.
Hãy xem một ví dụ về cách hai quá trình di chuyển qua các trạng thái này. Để bắt đầu, hãy tưởng tượng rằng cả hai tiến trình đều đang chạy và mỗi tiến trình chỉ sử dụng CPU. Trong trường hợp này, trạng thái của họ sẽ như thế này.

Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Trong ví dụ sau, quy trình đầu tiên, sau một thời gian chạy, sẽ yêu cầu IO và chuyển sang trạng thái BLOCKED, cho phép một quy trình khác chạy (Hình 1.4). HĐH nhận thấy rằng quy trình 0 không sử dụng CPU và bắt đầu quy trình 1. Trong khi quy trình 1 đang chạy, IO được hoàn thành và trạng thái của quy trình 0 thay đổi thành SẴN SÀNG. Cuối cùng, quy trình 1 đã hoàn thành và sau khi hoàn thành, quy trình 0 sẽ bắt đầu, thực thi và kết thúc công việc của nó.

Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Cấu trúc dữ liệu

Bản thân hệ điều hành là một chương trình và giống như bất kỳ chương trình nào khác, nó có một số cấu trúc dữ liệu chính giúp theo dõi nhiều thông tin liên quan khác nhau. Để theo dõi trạng thái của từng tiến trình, hệ điều hành sẽ hỗ trợ một số danh sách quy trình cho tất cả các quy trình ở trạng thái SẴN SÀNG và một số thông tin bổ sung để theo dõi các quy trình hiện đang chạy. Ngoài ra, hệ điều hành nên giám sát các tiến trình bị chặn. Sau khi IO hoàn tất, HĐH phải đánh thức tiến trình được yêu cầu và đưa nó vào trạng thái sẵn sàng chạy.

Ví dụ: HĐH phải duy trì trạng thái của các thanh ghi bộ xử lý. Tại thời điểm quá trình dừng lại, trạng thái của các thanh ghi được lưu trữ trong không gian địa chỉ của tiến trình và tại thời điểm hoạt động của nó tiếp tục, các giá trị của các thanh ghi sẽ được khôi phục và do đó tiếp tục thực hiện quá trình này.

Ngoài các trạng thái sẵn sàng, bị chặn, đang chạy, còn có một số trạng thái khác. Đôi khi, tại thời điểm tạo, một tiến trình có thể ở trạng thái INIT. Cuối cùng, một tiến trình có thể được đặt ở trạng thái CUỐI CÙNG khi nó đã hoàn thành nhưng thông tin của nó vẫn chưa bị xóa. Trên hệ thống UNIX trạng thái này được gọi là quá trình zombie. Trạng thái này hữu ích trong trường hợp tiến trình cha muốn biết mã trả về của tiến trình con, chẳng hạn, thường là 0 báo hiệu thành công và 1 là lỗi, nhưng người lập trình có thể đưa ra mã đầu ra bổ sung để báo hiệu các vấn đề khác nhau. Khi tiến trình cha kết thúc, nó thực hiện lệnh gọi hệ thống cuối cùng, chẳng hạn như wait(), để đợi tiến trình con kết thúc và báo hiệu cho HĐH rằng nó có thể xóa mọi dữ liệu liên quan đến tiến trình đã kết thúc.

Hệ điều hành: Ba phần dễ dàng. Phần 2: Trừu tượng hóa: Quy trình (bản dịch)

Những điểm chính của bài giảng:

quá trình — sự trừu tượng hóa chính của một chương trình đang chạy trong hệ điều hành. Tại bất kỳ thời điểm nào, một quá trình có thể được mô tả theo trạng thái của nó: nội dung của bộ nhớ trong không gian địa chỉ của nó, nội dung của các thanh ghi bộ xử lý, bao gồm con trỏ lệnh và con trỏ ngăn xếp và thông tin IO, chẳng hạn như các tệp đang mở được đọc hoặc ghi.
API quy trình bao gồm các lệnh gọi mà chương trình có thể thực hiện tới các tiến trình. Thông thường, đây là các cuộc gọi tạo, xóa hoặc các cuộc gọi khác.
● Quá trình đang ở một trong nhiều trạng thái, bao gồm đang chạy, sẵn sàng, bị chặn. Các sự kiện khác nhau như lập lịch, ngoại lệ từ việc lập lịch hoặc chờ đợi có thể thay đổi trạng thái của một quy trình từ quy trình này sang quy trình khác.
Danh sách xử lý chứa thông tin về tất cả các tiến trình trong hệ thống. Mỗi mục trong đó được gọi là khối điều khiển quy trình, trên thực tế là một cấu trúc chứa tất cả thông tin cần thiết về một quy trình cụ thể. 

Nguồn: www.habr.com

Thêm một lời nhận xét