New FAMILUG

Thursday, 26 March 2015

Kiểm tra một process đang chạy hay không (dựa vào PID)?

NOTICE: bài viết tập trung vào vấn đề "kiểm tra xem một process có đang chạy hay không dựa vào PID đã biết"

Tất nhiên cách thô thiển nhất là gõ ps auxww | grep PID để tìm, nhưng bài viết này không viết về cái thô thiển ấy.

Trên Linux, có sử dụng một thứ gọi là proc filesystem. Với mỗi process đang chạy có pid là PID, sẽ tồn tại tương ứng một thư mục /proc/PID

Vậy trên các OS sử dụng Linux, có thể kiểm tra thư mục này có tồn tại không là sẽ biết process có đang chạy hay không.
# ps -ef | grep bin[d]
bind     32511     1  0 05:33 ?        00:00:00 /usr/sbin/named -u bind
# python -c 'import os; print os.path.isdir("/proc/32511")'
True
# process với PID 32519 không tồn tại
# python -c 'import os; print os.path.isdir("/proc/32519")' && ps -ef | grep [3]2519
False
Có vẻ đã bớt thô thiển hơn nhiều, nhưng cách này chỉ áp dụng được với các hệ điều hành dùng Linux (và một số hệ điều hành hỗ trợ procfs thanks +Le Manh Cuong) . Vậy còn cách nào hơn? có thể chạy trên OS X, BSD ...?

Kill it!

# whatis kill
kill (1)             - send a signal to a process
kill (2)             - send signal to a process
Mặc dù tên chương trình là ``kill`` nhưng bản chất là nó gửi một signal (tín hiệu) đến một process.
Chú ý, để có man 2 kill, cần phải cài gói ``manpages-dev``.

Trong man 2 kill có viết: kill() system call gửi signal ``sig`` đến  ``pid`` (một hoặc một nhóm process). Giá trị của sig là các giá trị mô tả trong man 2 sigaction hoặc có thể là ``0``, khi gửi đi sig = 0, cơ chế kiểm tra lỗi vẫn được thực hiện nhưng không có signal nào được gửi đi thực sự.
Tức nếu PID đó không tồn tại, sẽ báo lỗi, còn nếu nó tồn tại thì không có gì xảy ra.
Sysadmin version:
# kill -s 0 32511 # không có gì xảy ra, process đang chạy
# kill -s 0 32519
-bash: kill: (32519) - No such process  # báo lỗi, process không tồn tại.

Python 2.7 CLI:
# python -c 'import os; os.kill(32511, 0)' # không có gì xảy ra
# python -c 'import os; os.kill(32519, 0)'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
OSError: [Errno 3] No such process
Vậy để kiểm tra một process có PID nào đó có đang chạy không, có thể sử dụng system call ``kill`` gửi đi signal 0 và xử lý kết quả trả về.
Happy killing!

by hvn@familug.org
ở một nơi xa xôi không ai biết tới

9 comments:

  1. "nhưng cách này chỉ áp dụng được với các hệ điều hành dùng Linux." ==> Điều này không đúng. Có khá nhiều HĐH ngoài Linux có sử dụng procfs, ví dụ: AIX, Solaris, Plan 9, NetBSD có thể giả lập `/proc` như linux.

    Một điều cần lưu ý nữa là khi `kill -s 0` thành công chỉ đảm bảo là process với PID và đủ permission đang chạy, điều này không đảm bảo đó là process mà bạn mong muốn. Ví dụ chạy vài câu lệnh sleep, kill -s 0 -- $(pgrep sleep) có thể fail một trong các sleep process "died" trong khi pgrep và kill đang chạy.

    ReplyDelete
  2. > ví dụ: AIX, Solaris, Plan 9, NetBSD có thể giả lập `/proc` như linux.
    cám ơn bạn, mình đã update bài viết.

    > điều này không đảm bảo đó là process mà bạn mong muốn
    mình không hiểu rõ chỗ này lắm, ý bạn là việc một process cũ die và 1 process mới có thể dùng PID của process cũ đã die?

    ReplyDelete
  3. Đúng rồi bạn. Mình chỉ muốn nhấn mạnh 1 điểm là việc monitor 1 process mà dựa vào PID của nó thì có thể không chính xác.

    Cách tốt nhất là dựa vào Parent của thằng process.

    ReplyDelete
    Replies
    1. như mình biết thì các tool monitor 1 process (nrpe/diamond) đều sử dụng tên process (name/exe/cmdline). Bài viết này chủ yếu nhằm tới một process có PID xác định có đang chạy không (mình sẽ update vào bài viết).
      Còn dựa vào parent thì có vẻ không hợp lý (rất nhiều process cùng có parent PID = 1)

      Delete
    2. Parent cũng manage process bằng PID mà bạn :D

      Bài này chỉ là dùng tool để kiểm tra nên việc kiểm tra sẽ không thể chính xác như là parent quản lý các tiến trình con được.

      Delete
  4. @Hưng Việt Nguyễn: Tại sao lại không hợp lý? Việc rất nhiều process cùng có parent PID = 1 không liên quan đến việc monitor này.

    Một process PID sẽ không được sử dụng lại cho đến khi parent của nó công nhận là nó die (Đó là lý do tại sao có zombie process, khi mà parent process không thế xác nhận là PID die).

    ReplyDelete
    Replies
    1. bạn có thể đưa ra 1 ví dụ (script?) để thực hiện việc manage một process sử dụng PPID của nó không? như trong ví dụ chạy vài câu lệnh sleep và dùng kill -0 ...

      Delete
  5. Hình như bạn có chút hiểu lầm ở đây. Mình nói là dựa vào parent chứ không phải sử dụng PPID.

    Ví dụ điển hình là trong bash, khi bạn thực hiện 1 lệnh ở background (cmd &) sau đó dùng builtin wait, thì lúc này bash script chỉ quit khi command thực hiện xong. Tức là bạn đã giao việc manage process chạy cmd cho parent của nó, là bash.

    Nếu không dùng wait thì bash quit ngay, trong khi cmd vẫn đang chạy và chuyển PPID sang 1.

    $ cat > test.sh
    #!/bin/bash

    echo start
    sleep 60 &
    echo end

    ReplyDelete
    Replies
    1. đúng là có hiểu lầm ở đây, vì bày này mình viết nhằm tới việc kiểm tra một PID có đang chạy không từ bên ngoài (vd nrpe script) chứ không định monitor nó theo nghĩa manage process từ phía parent với subprocess.

      Cám ơn bạn đã dành thời gian để thảo luận về bài viết, rất mong bạn tiếp tục đưa ra những thảo luận bổ ích trong các bài sau.

      Delete