Làm thế nào để kiểm tra xem một PID đã cho có đang chạy không?


16

Tôi đang viết một tập lệnh Perl để phân tích cú pháp logfiles để thu thập các PID và sau đó kiểm tra xem liệu PID đó có đang chạy hay không. Tôi đang cố gắng nghĩ ra cách tốt nhất để thực hiện kiểm tra đó. Rõ ràng, tôi có thể làm một cái gì đó như:

system("ps $pid > /dev/null") && print "Not running\n";

Tuy nhiên, tôi muốn tránh cuộc gọi hệ thống nếu có thể. Do đó, tôi nghĩ rằng tôi có thể sử dụng /prochệ thống tập tin (tính di động không phải là vấn đề đáng lo ngại, điều này sẽ luôn chạy trên hệ thống Linux). Ví dụ:

if(! -d "/proc/$pid"){
    print "Not running\n";
}

Điều đó có an toàn không? Tôi có thể luôn luôn nghĩ rằng nếu không có /proc/$pid/thư mục thì PID liên quan không chạy? Tôi hy vọng như vậy vì psbản thân AFAIK cũng nhận được thông tin từ /procđó nhưng vì đây là mã sản xuất, tôi muốn chắc chắn.

Vì vậy, có thể có trường hợp một quy trình đang chạy không có /proc/PIDthư mục hoặc nơi /proc/PIDthư mục tồn tại và quy trình không chạy? Có bất kỳ lý do để thích phân tích cú pháp pshơn kiểm tra sự tồn tại của thư mục?


2
Ngoài ra còn có killchức năng perl sử dụng tín hiệu 0 không giết chết nhưng cho biết nếu bạn có thể làm như vậy (tức là bạn cần có quyền để báo hiệu quá trình đó).
meuh

1
'/ Proc / $ PID' sẽ ổn nếu bạn làm điều này trong Linux.
likewhoa

7
@terdon Lưu ý rằng bất kỳ phương pháp nào bạn sử dụng (và kill -0là phương pháp tốt nhất), điều này chỉ cho bạn biết liệu có một quy trình đang chạy với PID đã cho hay không . Nó không cho bạn biết liệu quy trình có còn chạy sau một phần nghìn giây hay không và nó không cho bạn biết liệu quy trình đó có phải là quy trình bạn quan tâm hay quy trình không liên quan đã được gán cùng một PID sau khi quy trình thú vị bị chết . Hầu như luôn luôn là một sai lầm để kiểm tra xem một PID nhất định có đang chạy hay không : có rất ít trường hợp điều này không dễ xảy ra trong điều kiện chủng tộc.
Gilles 'SO- đừng trở nên xấu xa'

1
@Gilles thực sự, tôi cũng nên kiểm tra tên quá trình. Tuy nhiên, trong trường hợp này, tôi không quan tâm nếu có trạng thái thay đổi một phần nghìn giây sau đó. Tôi có các quy trình được liệt kê là hoạt động theo dB và một tệp tương ứng với các pids. Tôi chỉ cần kiểm tra xem bất cứ thứ gì DB nghĩ là đang chạy không thực sự chạy và có đủ quyền kiểm soát thiết lập để biết rằng nó không thể khởi động lại một cách ngẫu nhiên.
terdon

3
@MickLH wow, đó là tôi đã nói. Đó thực sự sẽ là một bình luận hữu ích thay vì một kỷ niệm về sự sáng chói của chính bạn, bạn đã bận tâm để giải thích điều gì là xấu và nguy hiểm. Tôi không nghi ngờ bạn đúng, tôi chưa bao giờ tự nhận mình là một lập trình viên, đó là lý do tại sao tôi đặt câu hỏi, nhưng bạn đã quản lý để vừa xúc phạm vừa vô ích.
terdon

Câu trả lời:


20

Hàm perl kill(0,$pid)có thể được sử dụng.

Nếu mã trả về là 1 thì PID tồn tại và bạn được phép gửi tín hiệu đến nó.

Nếu mã trả về là 0 thì bạn cần kiểm tra $!. Nó có thể là EPERM (quyền bị từ chối) có nghĩa là quá trình tồn tại hoặc ESRCH trong trường hợp quy trình không tồn tại.

Nếu mã kiểm tra của bạn đang chạy như vậy rootthì bạn có thể đơn giản hóa việc này để chỉ kiểm tra mã trả về của kill; 0 => lỗi, 1 => ok

Ví dụ:

% perl -d -e 0

Loading DB routines from perl5db.pl version 1.37
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> print kill(0,500)
0
  DB<2> print $!
No such process
  DB<3> print kill(0,1)
0
  DB<4> print $!
Operation not permitted
  DB<5> print kill(0,$$)
1

Điều này có thể được thực hiện thành một chức năng đơn giản

use Errno;

sub test_pid($)
{
  my ($pid)=@_;

  my $not_present=(!kill(0,$pid) && $! == Errno::ESRCH);

  return($not_present);
}

print "PID 500 not present\n" if test_pid(500);
print "PID 1 not present\n" if test_pid(1);
print "PID $$ not present\n" if test_pid($$);

FWIW, tôi đã thêm một chức năng đơn giản cho thấy cách bạn có thể làm điều này.
Stephen Harris

Vâng, tôi nghĩ rằng tôi sẽ đi với điều này. Tôi đã xóa bình luận của mình vì tôi nhận ra rằng tất cả những gì tôi cần là if (!kill(0,$pid) && $! =~ /No such process/){ exit; }hoặc tương tự. Tôi thích Errnogiải pháp của bạn hơn mặc dù, cảm ơn. Trong khi tôi có thể đi với điều này, tôi sẽ đợi một lúc trong trường hợp bất kỳ ai cũng có thể trả lời câu hỏi Linux tiềm ẩn.
terdon

2
Nếu /procđược gắn kết thì mọi PID hiển thị trong không gian tên sẽ xuất hiện, do đó -d /proc/$pidthử nghiệm của bạn sẽ hoạt động ... nhưng nó liên quan đến việc đi ra hệ thống tập tin thay vì sử dụng các cuộc gọi hệ thống gốc.
Stephen Harris

Đó chính xác là những gì tôi muốn tránh, vâng.
terdon

2
@terdon: Tôi mới nhận ra sự nhầm lẫn của mình xuất phát từ thực tế là "cuộc gọi hệ thống" bạn thực sự có nghĩa là " systemcuộc gọi" - tức là một cuộc gọi đến systemchính chức năng, không phải là "cuộc gọi hệ thống" . Cái sau bạn không thể tránh, nhưng cái trước bạn chắc chắn có thể. Làm cho ý nghĩa bây giờ!
Mehrdad

6
  • Tôi chắc chắn 99,9% rằng việc kiểm tra xem có tồn tại (và là một thư mục) có độ tin cậy 98% như kỹ thuật hay không. Lý do tại sao 98% không phải là 100% là một điểm mà Stephen Harris đã chạm vào (và bật ra) trong một bình luận - cụ thể là, hệ thống tập tin có thể không được gắn kết. Nó có thể có giá trị để khẳng định rằng một hệ thống Linux mà không là một hư hỏng, hệ thống suy thoái - sau khi tất cả, mọi thứ như thế , và có lẽ sẽ không làm việc - và do đó sức mạnh này không phải là một vấn đề đối với một hệ thống sản xuất. Nhưng về mặt lý thuyết là có thể nó chưa bao giờ được gắn kết (mặc dù điều này có thể ngăn hệ thống chuyển sang trạng thái bình thường), nhưng chắc chắn nó có thể bị hủy bỏ (tôi đã thử nghiệm nó 1/proc/PIDkill 0/proc/procpstoplsof) và tôi tin rằng không có bất kỳ đảm bảo nào rằng nó sẽ tồn tại (nghĩa là không bắt buộc bởi POSIX). Và, trừ khi hệ thống hoàn toàn hos, killsẽ hoạt động.
  • Nhận xét của Stephen nói về việc đi ra ngoài hệ thống tập tin và sử dụng các cuộc gọi hệ thống bản địa. Tôi tin rằng đây phần lớn là cá trích đỏ.
    • Vâng, bất kỳ nỗ lực để truy cập /proc đòi hỏi phải đọc thư mục gốc để tìm các /prochệ thống tập tin. Điều này đúng cho bất kỳ nỗ lực để truy cập bất kỳ tập tin bằng một tên đường dẫn tuyệt đối, bao gồm mọi thứ trong /bin, /etc/dev. Điều này xảy ra thường xuyên đến mức thư mục gốc chắc chắn được lưu trong bộ nhớ trong toàn bộ thời gian (thời gian hoạt động) của hệ thống, vì vậy bước này có thể được thực hiện mà không cần bất kỳ I / O đĩa nào. Và, một khi bạn có inode /proc, mọi thứ khác xảy ra đều nằm trong bộ nhớ.
    • Làm thế nào để bạn truy cập /proc? Với stat, open, readdir, vv, mà là hệ thống bản địa gọi mỗi bit càng nhiều càng tốt kill.
  • Câu hỏi nói về một quá trình đang chạy. Đây là một cụm từ trơn. Nếu bạn thực sự muốn kiểm tra xem quy trình có đang chạy hay không (nghĩa là trong hàng đợi chạy; có thể là quy trình hiện tại trên một số CPU; không ngủ, chờ hoặc dừng), bạn có thể cần phải thực hiện và đọc đầu ra hoặc xem . Nhưng tôi thấy không có gợi ý trong câu hỏi hoặc ý kiến ​​của bạn rằng bạn quan tâm đến điều này.ps PID /proc/PID/stat

    Tuy nhiên, con voi trong phòng là một quá trình zombie 2 có thể khó phân biệt với một quá trình còn sống và tốt.  kill 0hoạt động trên một zombie, và tồn tại. Bạn có thể xác định zombie bằng các kỹ thuật được liệt kê trong đoạn trước (thực hiện và đọc đầu ra hoặc nhìn vào ). Tôi rất nhanh chóng và giản dị (tức là, không phải là rất kỹ lưỡng) thử nghiệm cho thấy rằng bạn cũng có thể làm điều này bằng cách thực hiện một hoặc trên , hoặc - đây sẽ thất bại trên zombies. (Tuy nhiên, họ cũng sẽ thất bại trong các quy trình bạn không sở hữu.)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  nếu tùy chọn -f( f orce) không hoạt động, hãy thử -l( l azy).
2  tức là một quá trình đã thoát / chết / chấm dứt, nhưng cha mẹ vẫn chưa thực hiện a wait.


Cảm ơn bình luận của bạn về câu trả lời của tôi, mà tôi đã xóa vì nó sai. Tôi không tin rằng kill(2)trang này chỉ ra trực tiếp hành vi bạn đã chỉ ra, nhưng perlfunctrang này thì có. Tôi sẽ gửi email cho Michael Kerrisk để xem anh ấy nói gì về trang web của hệ thống.
jrw32982 hỗ trợ Monica

Tôi đã gửi một báo cáo lỗi để làm rõ trang hướng dẫn kill(2)về quyền cho phép "gửi" tín hiệu 0.
jrw32982 hỗ trợ Monica

@ jrw32982: Vâng, man page nói những câu như, “The sig luận ... có thể là 0, trong đó kiểm tra trường hợp lỗi được thực hiện ...” và “ LỖI - Các kill () gọi hệ thống sẽ thất bại và không có tín hiệu sẽ được gửi nếu: Quá trình gửi không phải là siêu người dùng và id người dùng hiệu quả của nó không khớp với id người dùng hiệu quả của quá trình nhận. Bây giờ bạn đề cập đến nó, tôi cho rằng có thể diễn giải theo nhiều cách, nhưng thật đáng tiếc, nhiều trang người dùng Unix được viết theo phong cách này, yêu cầu bạn phải đọc giữa các dòng. Michael có thể tin rằng nó đủ rõ ràng như nó là.
G-Man nói 'Phục hồi Monica'

Michael đã thực hiện một thay đổi cho kill(2)trang này (Tôi chưa thấy nó trực tuyến): "Nếu sig là 0, thì không có tín hiệu nào được gửi, nhưng kiểm tra sự tồn tại và quyền vẫn được thực hiện; điều này có thể được sử dụng để kiểm tra sự tồn tại của một ID tiến trình hoặc ID nhóm quy trình mà người gọi được phép báo hiệu. "
jrw32982 hỗ trợ Monica
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.