Bagaimana cara mengganti semua utas (dan anak-anak) dari satu proses di Linux?

22

Linux (belum) mengikuti standar POSIX.1 yang mengatakan bahwa renicepada suatu proses mempengaruhi "semua utas lingkup sistem dalam proses", karena menurut pthreads (7) doc "utas tidak berbagi nilai bagus yang sama".

Namun, kadang-kadang, akan lebih mudah untuk renice"semuanya" terkait dengan proses yang diberikan (salah satu contohnya adalah proses anak Apache dan semua utasnya). Begitu,

  • bagaimana saya bisa renicesemua utas menjadi bagian dari proses yang diberikan?
  • bagaimana saya renicesemua proses anak milik proses yang diberikan?

Saya mencari solusi yang cukup mudah.

Saya tahu bahwa kelompok proses kadang-kadang bisa membantu, namun, mereka tidak selalu cocok dengan yang ingin saya lakukan: mereka dapat mencakup serangkaian proses yang lebih luas atau berbeda.

Menggunakan cgroupdikelola oleh systemdmungkin juga bermanfaat, tetapi bahkan jika saya tertarik untuk mendengarnya, saya kebanyakan mencari solusi "standar".

EDIT: juga, man (7) pthreadsmengatakan "semua utas dalam suatu proses ditempatkan dalam grup utas yang sama; semua anggota grup utas berbagi PID yang sama". Jadi, apakah mungkin untuk renicesesuatu yang tidak memiliki PID sendiri?

Totor
sumber

Jawaban:

19

Anda dapat menggunakan /proc/$PID/taskuntuk menemukan semua utas proses yang diberikan, karena itu Anda dapat menggunakan

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

untuk renicesemua utas yang dimiliki proses tertentu.

Cara yang sama /proc/$PID/task/$PID/childrendapat digunakan untuk menemukan semua proses anak (atau /proc/$PID/task/*/childrenjika Anda ingin semua proses anak dari semua utas proses tertentu).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO
Anton Leontiev
sumber
man (7) pthreadsmengatakan tentang implementasi saat ini (NPTL): "semua utas dalam suatu proses ditempatkan dalam grup utas yang sama; semua anggota grup utas berbagi PID yang sama" dan "Utas tidak berbagi nilai bagus yang sama". Lalu, bagaimana Anda bisa mengganti utas yang tidak memiliki PID sendiri, saat renicemenggunakan PID untuk melakukannya?
Totor
Saya mencoba renice pada ID utas, dan dilaporkan 24995 (process ID) old priority 0, new priority -10. 24995 tidak muncul ps, jadi itu bukan proses. Mungkin mengganti benang benar-benar berfungsi?
Stefan Reich
9

Nilai bagus atau pembagian CPU?

Harap dicatat bahwa saat ini, nilai yang bagus mungkin tidak begitu relevan "seluruh sistem", karena pengelompokan tugas otomatis, terutama ketika menggunakan systemd . Silakan lihat jawaban ini untuk lebih jelasnya.

Perbedaan antara utas dan proses

Pertanyaan penting di Linux, karena dokumentasi melanggengkan keraguan (tentang utas yang tidak memiliki PID sendiri misalnya).

Catatan: jawaban ini menjelaskan thread Linux dengan tepat.

Singkatnya: kernel hanya menangani "entitas yang dapat dijalankan ", yaitu sesuatu yang dapat dijalankan dan dijadwalkan . Kernel bijaksana, entitas ini disebut proses. Utas, adalah sejenis proses yang berbagi (setidaknya) ruang memori dan penangan sinyal dengan yang lain.

Setiap proses tersebut memiliki pengidentifikasi unik seluruh sistem: PID (Process ID). Untuk apa yang disebut utas, terkadang disebut TID (Utas ID), tetapi dari sudut pandang sysadmin (dan kernel!), TID dan PID adalah hal yang sama (mereka berbagi namespace yang sama).

Hasilnya, Anda dapat renice masing - masing "utas" secara individual karena mereka memiliki PID 1 mereka sendiri .

Menemukan semua PID renice secara rekursif

Kita perlu mendapatkan PID dari semua proses ("normal" atau "utas") yang merupakan turunan (anak-anak atau dalam grup utas) dari proses yang akan dilakukan. Ini harus bersifat rekursif (mempertimbangkan anak-anak anak-anak).

Jawaban Anton Leontiev memberikan petunjuk untuk melakukannya: semua nama folder /proc/$PID/task/adalah PID utas yang berisi childrenfile yang berisi daftar proses anak-anak yang potensial.

Namun, ini kurang berulang, jadi inilah skrip shell cepat & kotor untuk menemukannya:

#!/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

Jika proses PID 1234 adalah yang Anda inginkan secara rekursif bagus, sekarang Anda dapat melakukannya:

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

1 Perhatikan bahwa, untuk kepatuhan POSIX, panggilan getpid(2)dalam utas tidak akan memberi Anda ID unik (PID) seluruh sistem dari entitas yang dapat dijalankan ini, melainkan PID dari proses utama dalam "grup utas". Anda harus menelepon gettid(2)saja. Lihat jawaban ini untuk informasi lebih lanjut.

Totor
sumber
6

Kita seharusnya tidak membingungkan proses PID dan id utas kadang ditulis TID atau dalam perintah ps LPW. The sperintah memiliki pilihan untuk benang layar, dan di bawah topatau htopAnda beralih antara benang dan proses dengan Hsurat. Seperti yang diceritakan sebelumnya oleh @Totor, dengan NPTL, yang merupakan implementasi saat ini dengan kernel> 2.6, semua utas memiliki pid yang sama, tetapi mereka memiliki tid yang berbeda. Anda menunjukkan semua utas proses dengan:

$ ps -Ljf <pid>

Ini adalah nama-nama direktori di bawah /proc/<pid>/task, dan bahkan jika renice (1) mengatakan bahwa argumen defaultnya adalah pid ketika diterapkan pada pid, ia hanya mengganti utas utama (ini adalah bug dalam implementasi linux seperti yang ditulis dalam setpriority (2 ) ), itu juga dapat diterapkan pada tid dan itu mengubah nama utas. Itulah mengapa jawaban @Anton valid.

Tetapi paling sering ada cara yang lebih mudah untuk mencapai hasil yang diinginkan, semua utas ini berbagi pgid yang sama yang merupakan pid dari pemimpin kelompok; Anda dapat mengganti nama dengan pgid dengan menerbitkan:

$ renice -g <pgid>

Jika Anda tidak ingin mengubah proses lain yang bergantung pada pemimpin grup yang sama, Anda harus menggunakan resep @ Anton:

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

atau:

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

Anda mungkin juga ingin tahu apa saja proses lain dari grup yang sama dari proses yang ingin Anda renice, yaitu proses yang berbagi memiliki pgid yang sama. Anda dapat menggunakan ps (1) , pstidak memungkinkan untuk memilih proses oleh ketua grup, tetapi Anda dapat meminta psuntuk melakukannya. Proses dengan pgid 1908akan diberikan oleh perintah:

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

atau jika Anda lebih suka awk daripada sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
marcz
sumber
Ini sepertinya tidak berfungsi dengan benar pada 4.19.4 (Debian Stretch seperti sekarang): $ 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;}' Sedangkan metode Totor masih / masih berfungsi: $ /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 ... Saya sudah mengkonfirmasi dengan / proc, htop, pstree, dll. Bahwa saya memang memiliki top- top yang benar PID tingkat. Mungkin ada yang berubah dalam satu tahun terakhir.
Bill McGonigle
Saya tidak tahu bagaimana Anda membuat pengujian Anda @ bill-mcgonigle, saya baru saja mencoba dengan tiga kernel 4.9.0 pada Debian Stretch; 4.18.0 dan 4.19.0 pada pengujian Debian; Dan itu berfungsi seperti yang saya katakan di atas.
marcz
Seperti yang saya katakan, Debian Stretch pada 4.19.4 dengan perintah dan output ditampilkan; perbedaannya tampaknya 4.19.0 vs 4.19.4 tapi saya terkejut akan ada banyak perubahan antara versi minor tersebut.
Bill McGonigle
Saya kira proses Anda 8524 adalah PID dari semua proses berurutan TID atau LPW, tetapi bukan grup proses, jadi tentu saja Anda menemukan semua utas /proc/8524/tasktetapi renice -ggagal. Saat Anda melihat pohon proses, satu cabang berada di grup proses yang sama, tidak hanya satu proses berulir. Coba lagi periksa hasil ps -Ljf.
marcz
0

Saya ingin merekomendasikan menggunakan argumen -g (grup proses) alih-alih -p (proses id) saat menggunakan renice. Itu melakukan hal yang sama tanpa bash-foo.

yaitu

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>
user12042
sumber
Jawaban marcz sudah menyebutkan ini.
Totor
-1

Berikut ini skrip saya:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
Antonio Petricca
sumber
1
Ini meluncurkan renice pada setiap proses kecuali yang Anda sebut. Saya pribadi menganggap perintah ini berbahaya dan tidak memadai.
Totor
Saya bertanya-tanya apakah dia bermaksud -w bukan -v
Diablo-D3