Các trạng thái quy trình Linux


89

Trong Linux, điều gì xảy ra với trạng thái của một tiến trình khi nó cần đọc các khối từ đĩa? Nó có bị chặn không? Nếu vậy, quy trình khác được chọn để thực thi như thế nào?

Câu trả lời:


86

Trong khi chờ đợi read()hoặc write()đến / từ một bộ mô tả tệp trả về, quá trình sẽ được đặt trong một kiểu ngủ đặc biệt, được gọi là "D" hoặc "Disk Sleep". Điều này là đặc biệt, bởi vì quá trình không thể bị giết hoặc bị gián đoạn trong trạng thái như vậy. Quá trình chờ trả về từ ioctl () cũng sẽ được chuyển sang trạng thái ngủ theo cách này.

Một ngoại lệ cho điều này là khi một tệp (chẳng hạn như thiết bị đầu cuối hoặc thiết bị ký tự khác) được mở ở O_NONBLOCKchế độ, được chuyển khi nó giả định rằng một thiết bị (chẳng hạn như modem) sẽ cần thời gian để khởi tạo. Tuy nhiên, bạn đã chỉ ra các thiết bị chặn trong câu hỏi của mình. Ngoài ra, tôi chưa bao giờ thử một ứng dụng ioctl()có khả năng chặn trên fd được mở ở chế độ không chặn (ít nhất là không cố ý).

Cách chọn một quy trình khác hoàn toàn phụ thuộc vào bộ lập lịch mà bạn đang sử dụng, cũng như những gì các quá trình khác có thể đã thực hiện để sửa đổi trọng số của chúng trong bộ lập lịch đó.

Một số chương trình không gian người dùng trong những trường hợp nhất định đã được biết là vẫn ở trạng thái này mãi mãi, cho đến khi khởi động lại. Chúng thường được nhóm chung với các "thây ma" khác, nhưng thuật ngữ này sẽ không chính xác vì chúng không tồn tại về mặt kỹ thuật.


1
"Quá trình chờ đợi trả về từ ioctl () cũng sẽ được chuyển sang trạng thái ngủ theo cách này". Tôi vừa giết quá trình không gian người dùng của mình đang chờ IOCTL chặn nên điều này không đúng. Trừ khi tôi là missunderstanding
Hamzahfrq

Sẽ rất khó để tính thời gian một bài kiểm tra như vậy. Các quy trình liên tục không thể bị giết; nếu bạn có thể giết nó, thì nó chỉ đơn giản là chặn (hạt nhân không nằm ở giữa bất kỳ phần nào của ioctl và sao chép bất kỳ phản hồi tương ứng nào vào không gian người dùng tại vị trí bạn đã vượt qua (hoặc ít nhất là không nằm trong giữa sao chép)). Linux cũng đã thay đổi rất nhiều kể từ năm 2009 khi điều này được viết ra; hiện tượng này ít quan sát được như trước đây.
Tim Post

133

Khi một quy trình cần tìm nạp dữ liệu từ đĩa, quy trình đó sẽ dừng chạy trên CPU một cách hiệu quả để cho các quy trình khác chạy vì hoạt động có thể mất nhiều thời gian để hoàn thành - thời gian tìm kiếm đĩa ít nhất là 5 mili giây và 5 mili giây là 10 triệu Chu kỳ CPU, một sự vĩnh cửu theo quan điểm của chương trình!

Theo quan điểm của lập trình viên (cũng được cho là "trong không gian người dùng"), đây được gọi là lệnh gọi hệ thống chặn . Nếu bạn gọi write(2)(là một trình bao bọc libc mỏng xung quanh lệnh gọi hệ thống cùng tên), quá trình của bạn không chính xác dừng lại ở ranh giới đó; nó tiếp tục, trong nhân, chạy mã lệnh gọi hệ thống. Hầu hết thời gian nó đi đến một trình điều khiển bộ điều khiển đĩa cụ thể (tên tệp → hệ thống tệp / VFS → thiết bị khối → trình điều khiển thiết bị), trong đó lệnh để tìm nạp một khối trên đĩa được gửi đến phần cứng thích hợp, đó là rất hoạt động nhanh chóng trong hầu hết thời gian.

SAU ĐÓ tiến trình được đặt ở trạng thái ngủ (trong không gian hạt nhân, việc chặn được gọi là ngủ - không có gì bị 'chặn' theo quan điểm của hạt nhân). Nó sẽ được đánh thức sau khi phần cứng cuối cùng đã tìm nạp dữ liệu thích hợp, sau đó quá trình sẽ được đánh dấu là có thể chạy được và sẽ được lên lịch. Cuối cùng, bộ lập lịch sẽ chạy quá trình.

Cuối cùng, trong không gian người dùng, lệnh gọi hệ thống chặn trả về với trạng thái và dữ liệu phù hợp, và dòng chương trình tiếp tục.

Có thể gọi hầu hết các lệnh gọi hệ thống I / O ở chế độ không chặn (xem O_NONBLOCKtrong open(2)fcntl(2)). Trong trường hợp này, các lệnh gọi hệ thống trả về ngay lập tức và chỉ báo cáo việc gửi hoạt động của đĩa. Lập trình viên sẽ phải kiểm tra rõ ràng sau đó xem thao tác đã hoàn thành, thành công hay chưa và tìm nạp kết quả của nó (ví dụ: với select(2)). Đây được gọi là lập trình không đồng bộ hoặc dựa trên sự kiện.

Hầu hết các câu trả lời ở đây đề cập đến trạng thái D (được gọi TASK_UNINTERRUPTIBLEtrong tên trạng thái Linux) là không chính xác. Các D nhà nước là một chế độ đặc biệt giấc ngủ mà chỉ kích hoạt trong một đường dẫn mã không gian hạt nhân, khi mà đường dẫn mã không thể bị gián đoạn (vì nó sẽ là quá phức tạp để chương trình), với kỳ vọng rằng nó sẽ chặn chỉ cho một rất thời gian ngắn. Tôi tin rằng hầu hết các "trạng thái D" thực sự là vô hình; chúng tồn tại rất ngắn và không thể quan sát được bằng các công cụ lấy mẫu như 'top'.

Bạn có thể gặp phải các quy trình không thể xử lý được ở trạng thái D trong một vài tình huống. NFS nổi tiếng vì điều đó, và tôi đã gặp nó nhiều lần. Tôi nghĩ rằng có một cuộc xung đột ngữ nghĩa giữa một số đường dẫn mã VFS, giả sử luôn đến được đĩa cục bộ và phát hiện lỗi nhanh (trên SATA, thời gian chờ lỗi sẽ khoảng vài 100 mili giây) và NFS, thực sự lấy dữ liệu từ mạng. linh hoạt hơn và phục hồi chậm (thời gian chờ TCP 300 giây là phổ biến). Đọc bài viết này để biết giải pháp tuyệt vời được giới thiệu trong Linux 2.6.25 với TASK_KILLABLEtrạng thái. Trước thời đại này, đã có một vụ hack nơi bạn thực sự có thể gửi tín hiệu đến các máy khách xử lý NFS bằng cách gửi một SIGKILL tới chuỗi hạt nhân rpciod, nhưng hãy quên đi thủ thuật xấu xí đó.…


2
+1 cho câu trả lời chi tiết, nhưng xin lưu ý rằng chủ đề này đã có câu trả lời được chấp nhận trong gần hai năm. Nhấn vào liên kết "Câu hỏi" nếu bạn muốn giúp đỡ những câu hỏi gần đây hơn. Chào mừng bạn đến với Stack Overflow và cảm ơn bạn đã đóng góp!
GargantuChet

20
Câu trả lời này là câu trả lời duy nhất đề cập đến NFS, trong một số môi trường là cách giải thích phổ biến nhất cho các tiến trình ở trạng thái D. +1.
Pinko

14
Câu trả lời rất tốt, cảm ơn. Cũng lưu ý rằng quá trình chuyển sang trạng thái D trong khi chờ các trang đã được hoán đổi, do đó, quá trình đập sẽ ở trạng thái D trong một thời gian dài.
cha0site

@zerodeux câu trả lời hay, nhưng tôi nghĩ giản đồ của bạn (tên tệp -> hệ thống tệp / VFS -> khối thiết bị -> trình điều khiển thiết bị) nó phải là (tên tệp -> VFS -> hệ thống tệp (ext3) -> khối thiết bị -> trình điều khiển thiết bị)
c4f4t0r

1
Có an toàn không khi giả định rằng thời gian dành cho hạt nhân chờ đợi trên spinlock (có thể có hoặc không liên quan đến i / o đĩa) tất cả đều được báo cáo ở trạng thái D /proc/stat?
wick

8

Quá trình thực hiện I / O sẽ được đặt ở trạng thái D (trạng thái ngủ không gián đoạn) , giải phóng CPU cho đến khi có một ngắt phần cứng để CPU quay trở lại thực thi chương trình. Xem man pscác trạng thái quy trình khác.

Tùy thuộc vào hạt nhân của bạn, có một bộ lập lịch trình theo dõi một hàng loạt các quá trình sẵn sàng thực thi. Nó, cùng với một thuật toán lập lịch, cho kernel biết tiến trình nào cần gán cho CPU nào. Có các quy trình nhân và quy trình người dùng cần xem xét. Mỗi tiến trình được phân bổ một lát thời gian, là một phần thời gian CPU được phép sử dụng. Khi quá trình sử dụng tất cả thời gian của nó, nó được đánh dấu là đã hết hạn và được ưu tiên thấp hơn trong thuật toán lập lịch.

Trong kernel 2.6 , có một bộ lập lịch độ phức tạp thời gian O (1) , vì vậy bất kể bạn có bao nhiêu tiến trình đang chạy, nó sẽ chỉ định các CPU trong thời gian không đổi. Tuy nhiên, nó phức tạp hơn, vì quyền ưu tiên được giới thiệu 2.6 và cân bằng tải CPU không phải là một thuật toán dễ dàng. Trong mọi trường hợp, nó hoạt động hiệu quả và CPU sẽ không hoạt động trong khi bạn đợi I / O.


3

Như những người khác đã giải thích, các tiến trình ở trạng thái "D" (ngủ liên tục) chịu trách nhiệm cho quá trình ps bị treo. Đối với tôi, điều đó đã xảy ra nhiều lần với RedHat 6.x và các thư mục nhà NFS đã tự động đếm.

Để liệt kê các tiến trình ở trạng thái D, bạn có thể sử dụng các lệnh sau:

cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D

Để biết thư mục hiện tại của quá trình và có thể là đĩa NFS được gắn có vấn đề, bạn có thể sử dụng lệnh tương tự như ví dụ sau (thay 31134 bằng số quá trình đang ngủ):

# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug  2 16:25 /proc/31134/cwd -> /auto/pippo

Tôi nhận thấy rằng việc đưa ra lệnh umount bằng nút chuyển -f (force) cho hệ thống tệp nfs được gắn kết có liên quan, có thể đánh thức quá trình ngủ:

umount -f /auto/pippo

hệ thống tệp không được ngắt kết nối, vì nó đang bận, nhưng quá trình liên quan đã đánh thức và tôi có thể giải quyết vấn đề mà không cần khởi động lại.


1

Giả sử quy trình của bạn là một chuỗi duy nhất và bạn đang sử dụng chặn I / O, quy trình của bạn sẽ chặn chờ I / O hoàn tất. Kernel sẽ chọn một tiến trình khác để chạy trong thời gian chờ đợi dựa trên độ đẹp, mức độ ưu tiên, thời gian chạy cuối cùng, v.v. Nếu không có tiến trình có thể chạy nào khác, thì hạt nhân sẽ không chạy được nữa; thay vào đó, nó sẽ cho phần cứng biết rằng máy đang ở chế độ nhàn rỗi (điều này sẽ dẫn đến mức tiêu thụ điện năng thấp hơn).

Các quy trình đang chờ I / O hoàn tất thường hiển thị ở trạng thái D, ví dụ: pstop.


Tôi đã khởi chạy một số quy trình sử dụng khoảng 10% tổng bộ nhớ. Tôi nhận thấy rằng nhiều người trong số họ đang ở trạng thái D. Điều này có phải do IO chậm trên máy cụ thể này không? Giả sử tôi có 9 quy trình, chúng có thể đang cạnh tranh cho IO và nhiều trong số chúng ở trạng thái D.
Kemin Zhou,

@KeminZhou So với tốc độ CPU, I / O khá chậm — thậm chí I / O nhanh. Một quá trình I / O nặng đơn lẻ có thể dễ dàng làm bận ổ đĩa từ, thậm chí là ổ SSD. 10 I / O quy trình nặng có thể bận rộn khá nhiều.
derobert,

1

Có, tác vụ bị chặn trong lệnh gọi hệ thống read (). Một tác vụ khác đã sẵn sàng chạy hoặc nếu không có tác vụ nào khác sẵn sàng, tác vụ nhàn rỗi (cho CPU đó) sẽ chạy.

Việc đọc đĩa thông thường, bị chặn khiến tác vụ chuyển sang trạng thái "D" (như những người khác đã lưu ý). Các tác vụ như vậy góp phần vào mức trung bình tải, mặc dù chúng không tiêu tốn CPU.

Một số loại IO khác, đặc biệt là tty và mạng, không hoạt động hoàn toàn giống nhau - quá trình kết thúc ở trạng thái "S" và có thể bị gián đoạn và không được tính vào mức trung bình tải.


0

Có, các tác vụ chờ IO bị chặn và các tác vụ khác sẽ được thực thi. Việc chọn tác vụ tiếp theo được thực hiện bởi bộ lập lịch Linux .


0

Nói chung quá trình sẽ chặn. Nếu thao tác đọc trên bộ mô tả tệp được đánh dấu là không chặn hoặc nếu quá trình đang sử dụng IO không đồng bộ, nó sẽ không chặn. Ngoài ra, nếu quá trình có các chuỗi khác không bị chặn, chúng có thể tiếp tục chạy.

Quyết định về quá trình chạy tiếp theo là tùy thuộc vào bộ lập lịch trong nhân.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.