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

Tác giả Network Engineer, T.Tư 11, 2025, 12:07:24 CHIỀU

« Chủ đề trước - Chủ đề tiếp »

0 Thành viên và 1 Khách đang xem chủ đề.

1. Tổng quan

Trong bài viết này, chúng ta sẽ tìm hiểu về trạng thái tiến trình trong Linux. Cụ thể, chúng ta sẽ tìm hiểu về từng trạng thái trong năm trạng thái khác nhau của tiến trình Linux trong các phần khác nhau của vòng đời. Hơn nữa, chúng ta cũng sẽ xem xét các công cụ khác nhau mà chúng ta có thể sử dụng để đọc trạng thái của từng tiến trình trong hệ thống của mình.


2. Các trạng thái của tiến trình Linux

Trong Linux, một tiến trình là một trường hợp thực thi một chương trình hoặc lệnh. Trong khi các tiến trình này tồn tại, chúng sẽ ở một trong năm trạng thái có thể:

    Chạy hoặc có thể chạy (R)
    Giấc ngủ không gián đoạn (D)
    Giấc ngủ gián đoạn (S)
    Đã dừng lại (T)
    Thây ma (Z)

Để hình dung vòng đời của tiến trình, chúng ta có thể mô hình hóa nó trong một máy trạng thái hữu hạn:



Đối với bất kỳ tiến trình Linux nào, điểm khởi đầu của chúng là thời điểm chúng được tạo ra. Ví dụ, một tiến trình cha có thể khởi tạo một tiến trình con bằng cách sử dụng lệnh gọi hệ thống fork(). Sau khi bắt đầu, tiến trình sẽ chuyển sang trạng thái chạy hoặc có thể chạy. Trong khi tiến trình đang chạy, nó có thể đi vào một đường dẫn mã yêu cầu nó phải chờ các tài nguyên hoặc tín hiệu cụ thể trước khi tiếp tục. Trong khi chờ các tài nguyên, tiến trình sẽ tự nguyện từ bỏ các chu kỳ CPU bằng cách chuyển sang một trong hai trạng thái ngủ.

Ngoài ra, chúng ta có thể tạm dừng một tiến trình đang chạy và đưa nó vào trạng thái dừng. Thông thường, điều này được thực hiện bằng cách gửi tín hiệu SIGSTOP đến tiến trình. Một tiến trình ở trạng thái này sẽ tiếp tục tồn tại cho đến khi nó bị giết hoặc tiếp tục với SIGCONT. Cuối cùng, tiến trình hoàn thành vòng đời của nó khi nó bị chấm dứt và được đưa vào trạng thái zombie cho đến khi tiến trình cha của nó xóa nó khỏi bảng tiến trình.

2.1. Trạng thái đang chạy hoặc có thể chạy (R)

Khi một tiến trình mới được bắt đầu, nó sẽ được đưa vào trạng thái chạy hoặc có thể chạy. Ở trạng thái chạy, tiến trình chiếm một lõi CPU để thực thi mã và logic của nó. Tuy nhiên, thuật toán lập lịch luồng có thể buộc một tiến trình đang chạy từ bỏ quyền thực thi của nó. Điều này nhằm đảm bảo mỗi tiến trình có thể có một phần tài nguyên CPU công bằng. Trong trường hợp này, tiến trình sẽ được đưa vào hàng đợi chạy và trạng thái của nó hiện là trạng thái có thể chạy đang chờ đến lượt thực thi.

Mặc dù trạng thái đang chạy và có thể chạy là khác nhau nhưng chúng được nhóm lại thành một trạng thái duy nhất được biểu thị bằng ký tự R.

2.2. Trạng thái ngủ: Có thể ngắt quãng (S) và Không thể ngắt quãng (D)

Trong quá trình thực thi tiến trình, nó có thể bắt gặp một phần mã của nó cần yêu cầu tài nguyên bên ngoài. Chủ yếu, yêu cầu đối với các tài nguyên này dựa trên IO chẳng hạn như để đọc tệp từ đĩa hoặc thực hiện yêu cầu mạng. Vì tiến trình không thể tiếp tục nếu không có tài nguyên, nên nó sẽ dừng lại và không làm gì cả. Trong các sự kiện như thế này, chúng nên từ bỏ các chu kỳ CPU của mình cho các tác vụ khác đã sẵn sàng chạy và do đó chúng sẽ chuyển sang trạng thái ngủ.

Có hai trạng thái ngủ khác nhau: trạng thái ngủ không thể ngắt quãng (D) chờ các tài nguyên khả dụng trước khi chuyển sang trạng thái có thể chạy và không phản ứng với bất kỳ tín hiệu nào.

Hãy tưởng tượng một tiến trình đọc dữ liệu từ hệ thống lưu trữ được gắn trên mạng, như NFS (Hệ thống tệp mạng) hoặc SAN (Mạng lưu trữ). Nếu mạng chậm hoặc gặp sự cố, thao tác đọc có thể mất nhiều thời gian. Trong thời gian này, tiến trình sẽ bị chặn hiệu quả, chờ thao tác đọc mạng hoàn tất. Nó sẽ chuyển sang trạng thái D. Tiến trình không thể bị gián đoạn hoặc kết thúc ở trạng thái này vì nó đang chờ điều kiện phần cứng (trong trường hợp này là phản hồi của mạng). Điều này rất cần thiết để đảm bảo tính toàn vẹn và nhất quán của dữ liệu. Sau khi thao tác I/O mạng hoàn tất (thành công hoặc có lỗi), tiến trình sẽ thoát khỏi trạng thái D và tiếp tục thực thi hoặc xử lý bất kỳ lỗi nào xảy ra.

Mặt khác, trạng thái ngủ có thể ngắt (S) là trạng thái ngủ có thể ngắt (các trạng thái ngủ có thể ngắt) sẽ phản ứng với các tín hiệu và tính khả dụng của tài nguyên. Một tiến trình vào trạng thái S, hay Ngủ có thể ngắt, khi nó chờ một sự kiện hoặc điều kiện không liên quan trực tiếp đến hoạt động I/O.

Ví dụ, khi một tiến trình chờ người dùng nhập dữ liệu, hãy xem xét một ứng dụng dòng lệnh đang chạy trong một thiết bị đầu cuối, như trình soạn thảo văn bản hoặc shell. Khi ứng dụng này chờ người dùng nhập lệnh hoặc nhập văn bản, nó không cần sử dụng CPU. Để quản lý hiệu quả tài nguyên hệ thống, tiến trình sẽ chuyển sang trạng thái S (Ngủ có thể ngắt) trong khi chờ. Ở trạng thái này, tiến trình không thực thi bất kỳ mã nào; thay vào đó, nó đang chờ một sự kiện (trong trường hợp này là dữ liệu đầu vào của người dùng) xảy ra. Vì đang ở Trạng thái Ngủ có thể ngắt, nên tiến trình có thể được đánh thức bằng các tín hiệu, như tín hiệu cho biết người dùng đã nhấn một phím. Sau khi người dùng cung cấp dữ liệu đầu vào, tiến trình sẽ thức dậy, chuyển trở lại trạng thái R (Đang chạy), xử lý dữ liệu đầu vào và tiếp tục hoạt động của mình.

2.3. Trạng thái dừng (T)

Từ trạng thái chạy hoặc có thể chạy, chúng ta có thể đưa một tiến trình vào trạng thái dừng (T) bằng cách sử dụng tín hiệu SIGSTOP hoặc  SIGTSTP. Sự khác biệt giữa cả hai tín hiệu là chúng ta gửi SIGSTOP theo chương trình, chẳng hạn như chạy kill -STOP {pid}. Ngoài ra, tiến trình không thể bỏ qua tín hiệu này và sẽ chuyển sang trạng thái dừng. Mặt khác, chúng ta gửi tín hiệu SIGTSTP bằng cách sử dụng bàn phím CTRL + Z. Không giống như SIGSTOP, tiến trình có thể tùy ý bỏ qua tín hiệu này và tiếp tục thực thi khi nhận được SIGTSTP.

Khi ở trạng thái này, chúng ta có thể đưa tiến trình trở lại trạng thái đang chạy hoặc có thể chạy bằng cách gửi tín hiệu SIGCONT.

2.4. Trạng thái Zombie (Z)

Khi một tiến trình đã hoàn tất việc thực thi hoặc bị chấm dứt, nó sẽ gửi tín hiệu SIGCHLD  đến tiến trình cha và chuyển sang trạng thái zombie. Tiến trình zombie, còn được gọi là tiến trình không còn tồn tại, sẽ vẫn ở trạng thái này cho đến khi tiến trình cha xóa nó khỏi bảng tiến trình. Để xóa tiến trình con đã chấm dứt khỏi bảng tiến trình, tiến trình cha phải đọc giá trị thoát của tiến trình con bằng cách sử dụng các lệnh gọi hệ thống wait() hoặc  waitpid().

3. Kiểm tra trạng thái tiến trình

Có nhiều cách để kiểm tra trạng thái của một tiến trình trong Linux. Ví dụ, chúng ta có thể sử dụng các công cụ dòng lệnh như ps và  top để kiểm tra trạng thái của các tiến trình. Ngoài ra, chúng ta có thể tham khảo tệp trạng thái giả cho một PID cụ thể.

3.1. Hiển thị trạng thái tiến trình sử dụng ps

Để hiển thị trạng thái tiến trình bằng  lệnh ps, hãy chạy lệnh ps để bao gồm một cột cho biết trạng thái của tiến trình:

Mã nguồn [Chọn]
ps a
    PID TTY      STAT  TIME COMMAND
  2234 tty2    Ssl+  0:00 /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --systemd --session=ubuntu
  2237 tty2    Rl+    0:07 /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3
  2287 tty2    Sl+    0:00 /usr/libexec/gnome-session-binary --systemd --systemd --session=ubuntu
  2982 pts/0    Ss    0:00 bash
  3467 pts/0    R+    0:00 ps a

Chữ cái đầu tiên của giá trị bên dưới cột STAT  biểu thị trạng thái của tiến trình. Ví dụ, tiến trình có PID 2234 hiện đang ở trạng thái ngủ có thể ngắt, được biểu thị bằng ký tự S. Bên cạnh đó, chúng ta cũng có thể quan sát thấy tiến trình 2237 hiện đang ở trạng thái đang chạy hoặc có thể chạy.

Ngoài ra, chúng ta có thể thấy rằng có các ký tự bổ sung bên cạnh mỗi ký tự trạng thái. Các ký tự này biểu thị một số thuộc tính của trạng thái của tiến trình. Ví dụ, chữ cái in hoa s thấp hơn có nghĩa là tiến trình là người dẫn đầu phiên. Để biết danh sách đầy đủ về ý nghĩa của từng ký tự, chúng ta có thể tìm thấy trên trang hướng dẫn chính thức.

3.2. Sử dụng lệnh top

Trong Linux, công cụ dòng lệnh top hiển thị chi tiết tiến trình theo thời gian thực. Nó hiển thị các khía cạnh khác nhau của hệ thống, chẳng hạn như bộ nhớ và mức sử dụng CPU của từng tiến trình. Để xem trạng thái tiến trình, hãy chạy top trong terminal:

Mã nguồn [Chọn]
Tasks: 183 total,  1 running, 182 sleeping,  0 stopped,  0 zombie
%Cpu(s):  0.7 us,  1.1 sy,  0.0 ni, 97.1 id,  0.4 wa,  0.0 hi,  0.7 si,  0.0 st
MiB Mem :  3936.4 total,  1925.0 free,    850.6 used,  1160.8 buff/cache
MiB Swap:  2048.0 total,  2048.0 free,      0.0 used.  2834.2 avail Mem

    PID USER  PR  NI    VIRT    RES    SHR S  %CPU  %MEM    TIME+ COMMAND                                                                                                                           
  2237 bob  20  0  252252  81740  49204 S  2.3  2.0  0:09.37 Xorg                                                                                                                               
  2519 bob  20  0 3428664 375256 125080 S  2.0  9.3  0:19.57 gnome-shell                                                                                                                       
  2909 bob  20  0  966852  49944  37308 S  1.0  1.2  0:02.28 gnome-terminal-                                                                                                                   
      1 root  20  0  103500  13312  8620 S  0.7  0.3  0:04.44 systemd                                                                                                                                                                                                                                                   
  3588 bob  20  0  20600  3936  3380 R  0.3  0.1  0:00.01 top                                                                                                                               
      2 root  20  0      0      0      0 S  0.0  0.0  0:00.00 kthreadd                                                                                                                           
      3 root  0 -20      0      0      0 I  0.0  0.0  0:00.00 rcu_gp

Ở phần dưới cùng của đầu ra của lệnh top, chúng ta có thể tìm thấy cột S, hiển thị trạng thái của từng tiến trình. Trái ngược với lệnh ps,  lệnh top  hiển thị trạng thái của từng tiến trình mà không có thuộc tính tiến trình bổ sung.

3.3. Tệp giả /proc

Hệ thống tệp giả /proc chứa tất cả thông tin về các tiến trình trong hệ thống của chúng ta. Do đó, chúng ta có thể đọc trực tiếp trạng thái của một tiến trình thông qua hệ thống tệp giả này. Nhược điểm của cách tiếp cận này là trước tiên chúng ta cần biết PID của tiến trình trước khi có thể đọc trạng thái của nó.

Để có được trạng thái của một tiến trình, chúng ta có thể trích xuất giá trị từ tệp  trạng thái giả của nó trong /proc/{pid}/status. Ví dụ, chúng ta có thể có được trạng thái của tiến trình với PID 2519 bằng cách đọc tệp  /proc/2519/status :

Mã nguồn [Chọn]
cat /proc/2519/status | grep State
State:    S (sleeping)

4. Tóm tắt

Trong hướng dẫn này, chúng ta đã xem xét vòng đời của một tiến trình Linux. Hơn nữa, chúng ta đã học cách chúng ta có thể mô hình hóa vòng đời của một tiến trình Linux như một máy trạng thái hữu hạn. Sau đó, chúng ta đã xem xét năm trạng thái khác nhau khi một tiến trình Linux trải qua toàn bộ vòng đời. Cuối cùng, chúng ta kết thúc bài viết bằng các bản trình diễn về cách lấy trạng thái tiến trình Linux bằng nhiều công cụ khác nhau như ps, top và tệp giả /proc.