Làm cách nào để làm mới tất cả các luồng (và con) của một tiến trình trên Linux?


22

Linux không (chưa) tuân theo tiêu chuẩn POSIX.1 nói rằng một renicequy trình ảnh hưởng đến "tất cả các luồng phạm vi hệ thống trong quy trình", bởi vì theo các chủ đề pthreads (7) doc "không chia sẻ một giá trị tốt đẹp chung".

Tuy nhiên, đôi khi, có thể thuận tiện cho renice"mọi thứ" liên quan đến một quy trình nhất định (một ví dụ sẽ là các quy trình con của Apache và tất cả các luồng của chúng). Vì thế,

  • Làm thế nào tôi có thể renicetất cả các chủ đề thuộc về một quy trình nhất định?
  • Làm thế nào tôi có thể renicetất cả các quá trình con thuộc một quy trình nhất định?

Tôi đang tìm kiếm một giải pháp khá dễ dàng.

Tôi biết rằng các nhóm quy trình đôi khi có thể hữu ích, tuy nhiên, chúng không phải lúc nào cũng khớp với những gì tôi muốn làm: chúng có thể bao gồm một bộ quy trình rộng hơn hoặc khác nhau.

Sử dụng một cgroupquản lý bởi systemdcũng có thể hữu ích, nhưng ngay cả khi tôi muốn nghe về nó, tôi chủ yếu tìm kiếm một giải pháp "tiêu chuẩn".

EDIT: đồng thời, man (7) pthreadsnói rằng "tất cả các luồng trong một tiến trình được đặt trong cùng một nhóm luồng; tất cả các thành viên của một nhóm luồng đều có chung một PID". Vì vậy, thậm chí có khả năng đối với renicemột thứ không có PID riêng không?

Câu trả lời:


19

Bạn có thể sử dụng /proc/$PID/taskđể tìm tất cả các luồng của một quy trình nhất định, do đó bạn có thể sử dụng

$ ls /proc/$PID/task | xargs renice $PRIO

cho renicetất cả các chủ đề thuộc về một quy trình nhất định.

Cùng một cách /proc/$PID/task/$PID/childrencó thể được sử dụng để tìm tất cả các tiến trình con (hoặc /proc/$PID/task/*/childrennếu bạn muốn tất cả các tiến trình con của tất cả các luồng của một tiến trình đã cho).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO

man (7) pthreadsnói về việc triển khai (NPTL) hiện tại: "tất cả các luồng trong một quy trình được đặt trong cùng một nhóm luồng; tất cả các thành viên của nhóm luồng chia sẻ cùng một PID" và "Các luồng không chia sẻ một giá trị đẹp chung". Sau đó, làm thế nào bạn có thể gia hạn một luồng không có PID riêng, khi renicesử dụng PID để làm như vậy?
Totor

Tôi đã thử gia hạn trên một ID luồng, và nó báo cáo 24995 (process ID) old priority 0, new priority -10. 24995 không xuất hiện ps, vì vậy nó không phải là một quá trình. Có lẽ chủ đề renice-ing thực sự hoạt động?
Stefan Reich

9

Giá trị đẹp hay cổ phiếu CPU?

Xin lưu ý rằng ngày nay, các giá trị đẹp có thể không liên quan đến "toàn hệ thống", vì nhóm tác vụ tự động, đặc biệt khi sử dụng systemd . Xin vui lòng xem câu trả lời này để biết thêm chi tiết.

Sự khác biệt giữa các chủ đề và quy trình

Câu hỏi quan trọng trên Linux, bởi vì tài liệu tiếp tục tồn tại những nghi ngờ (ví dụ về các luồng không có PID riêng).

Lưu ý: câu trả lời này giải thích chính xác các luồng Linux.

Nói tóm lại: kernel chỉ xử lý "các thực thể có thể chạy", nghĩa là, một cái gì đó có thể được chạylên lịch . Kernel khôn ngoan, những thực thể này được gọi là quá trình. Một luồng, chỉ là một loại quy trình chia sẻ (ít nhất) không gian bộ nhớ và xử lý tín hiệu với một trình xử lý khác.

Mỗi quy trình như vậy có một mã định danh duy nhất trên toàn hệ thống: PID (ID quy trình). Đối với các chủ đề được gọi là, đôi khi nó được gọi là TID (ID luồng), nhưng theo quan điểm sysadmin (và kernel!), TID và PID là cùng một thứ (chúng có chung không gian tên).

Kết quả là, bạn có thể renice mỗi "luồng" riêng lẻ bởi vì chúng có PID 1 riêng .

Tìm tất cả các PID để renice đệ quy

Chúng ta cần phải có được các PID của tất cả các quy trình ("bình thường" hoặc "luồng") là hậu duệ (con hoặc trong nhóm luồng) của quy trình cần xử lý. Điều này nên được đệ quy (xem xét trẻ em của trẻ em).

Câu trả lời của Anton Leontiev đưa ra gợi ý để làm như vậy: tất cả các tên thư mục trong /proc/$PID/task/là các luồng của chủ đề chứa một childrentệp liệt kê các tiến trình con tiềm năng.

Tuy nhiên, nó thiếu đệ quy, vì vậy đây là tập lệnh shell nhanh & bẩn để tìm chúng:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

Nếu quy trình PID 1234 là quy trình bạn muốn đệ quy tốt, thì bây giờ bạn có thể làm:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

1 Lưu ý rằng, để tuân thủ POSIX, việc gọi getpid(2)trong một luồng sẽ không cung cấp cho bạn ID duy nhất trên toàn hệ thống (PID) của thực thể có thể chạy được này, mà thay vào đó là PID của quy trình chính trong "nhóm luồng". Bạn sẽ cần phải gọi gettid(2)thay thế. Xem câu trả lời này để biết thêm thông tin.


6

Chúng ta không nên nhầm lẫn giữa quá trình PID và id luồng đôi khi được viết TID hoặc trong lệnh ps LPW. Các slệnh có các tùy chọn cho chủ đề hiển thị, và dưới tophoặc htopbạn chuyển đổi giữa các chủ đề và xử lý bởi các Hlá thư. Như đã nói trước đây bởi @Totor, với NPTL, đây là cách triển khai hiện tại với kernel> 2.6, tất cả các luồng đều có cùng một pid, nhưng chúng có một tid riêng biệt. Bạn hiển thị tất cả các chủ đề của một quá trình bằng cách:

$ ps -Ljf <pid>

Các tid này là tên của các thư mục bên dưới /proc/<pid>/taskvà ngay cả khi renice (1) nói rằng đối số mặc định của nó là pid khi được áp dụng cho pid, nó chỉ đổi chủ đề chính (đây là một lỗi trong triển khai linux như được viết trong setp Warriority (2 ) ), nó cũng có thể được áp dụng cho một tid và nó làm mới chủ đề. Đó là lý do tại sao câu trả lời của @Anton là hợp lệ.

Nhưng hầu hết thường có một cách dễ dàng hơn để đạt được kết quả mong muốn, tất cả các chủ đề này đều có chung một pgid, đó là pid của trưởng nhóm; bạn có thể gia hạn bằng pgid bằng cách phát hành:

$ renice -g <pgid>

Nếu bạn không muốn gia hạn một số quy trình khác phụ thuộc vào cùng một nhóm trưởng, bạn phải sử dụng công thức của @ Anton:

$ renice <priority> $(ls -1 /proc/<pid>/task)

hoặc là:

$renice <priority> $(ps --no-header -Lo tid <pid>)

Bạn cũng có thể muốn biết các quy trình khác của cùng một nhóm là gì so với quy trình bạn muốn gia hạn, đó là các quy trình chia sẻ có cùng pgid. Bạn có thể sử dụng ps (1) , pskhông cho phép chọn các quy trình theo nhóm trưởng, nhưng bạn có thể grep a psđể làm điều đó. Các quy trình với pgid 1908sẽ được đưa ra bởi lệnh:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

hoặc nếu bạn thích awk hơn sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'

Điều này dường như không hoạt động chính xác trên 4.19.4 (Hiện tại Debian Stretch): $ renice -n 18 -g 8524 renice: failed to get priority for 8524 (process group ID): No such process $ ps --no-header axo pid,pgid|awk '{if ($2=="8524") print $1;}' Trong khi phương thức của Totor vẫn / vẫn hoạt động: $ /bin/ls /proc/8524/task | /usr/bin/xargs renice 19 2739 (process ID) old priority 19, new priority 19 2740 (process ID) old priority 19, new priority 19 ... Tôi đã xác nhận với / Proc, htop, pstree, v.v. mức độ PID. Có lẽ một cái gì đó đã thay đổi trong năm qua.
Bill McGonigle

Tôi không biết bạn đã thực hiện bài kiểm tra của mình như thế nào @ bill-mcgonigle, tôi vừa thử với ba nhân 4.9.0 trên Debian Stretch; 4.18.0 và 4.19.0 khi kiểm tra Debian; Và nó hoạt động như tôi đã nói ở trên.
marcz

Như tôi đã nói, Debian Trải dài trên 4.19.4 với các lệnh và đầu ra được hiển thị; sự khác biệt dường như là 4.19.0 so với 4.19.4 nhưng tôi ngạc nhiên sẽ có nhiều thay đổi giữa các phiên bản nhỏ như vậy.
Bill McGonigle

Tôi đoán quy trình 8524 của bạn là PID của tất cả quy trình luồng TID hoặc LPW, nhưng không phải là nhóm quy trình, vì vậy tất nhiên bạn tìm thấy tất cả các luồng trong /proc/8524/tasknhưng renice -gkhông thành công. Khi bạn nhìn vào một cây quy trình, một nhánh nằm trong cùng một nhóm quy trình, không chỉ một quy trình theo luồng. Hãy thử lại kiểm tra kết quả của ps -Ljf.
marcz

0

Tôi muốn khuyên bạn nên sử dụng đối số -g (nhóm quy trình) thay vì -p (id của quy trình) trong khi sử dụng renice. Nó làm điều tương tự mà không có bash-foo.

I E

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>

Câu trả lời của marcz đã đề cập đến điều này.
Totor

-1

Đây là một kịch bản của tôi:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>

1
Điều này khởi chạy renice trên mọi quy trình ngoại trừ quy trình bạn đặt tên. Tôi cá nhân coi lệnh này là nguy hiểm và không đầy đủ.
Totor

Tôi tự hỏi nếu anh ta có ý -w không -v
Diablo-D3
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.