web-dev-qa-db-ja.com

Linuxで1つのプロセスのすべてのスレッド(および子)を無効にする方法は?

Linuxは(まだ)POSIX.1標準に準拠していません 言います プロセスのreniceは「プロセス内のすべてのシステムスコープスレッド」に影響を与えると pthreads(7)doc 「スレッドは共通のナイス値を共有しない」。

ただし、特定のプロセスに関連するrenice "すべて"が便利な場合があります(1つの例は、Apacheの子プロセスとそのすべてのスレッドです)。そう、

  • 与えられたプロセスに属するrenice allthreadsはどうすればよいですか?
  • 与えられたプロセスに属するすべての子プロセスをどのようにreniceできますか?

かなり簡単な解決策を探しています。

プロセスグループ が役立つ場合があることはわかっていますが、それらは必ずしも私がやりたいことと一致するとは限りません。より広いまたは異なるプロセスのセットを含めることができます。

cgroupが管理するsystemdを使用することも役立つ場合がありますが、それについて知りたいと思っていても、ほとんどの場合「標準」の解決策を探しています。

編集:また、man (7) pthreadsは、「プロセス内のすべてのスレッドは同じスレッドグループに配置されます。スレッドグループのすべてのメンバーは同じPIDを共有します」と言います。それで、それ自身のPIDを持たないものをreniceすることも可能ですか?

23
Totor

良い値またはCPUシェア?

systemdを使用する場合は特に、自動タスクのグループ化のため、Nice値は「システム全体」ではそれほど関連性がない可能性があることに注意してください。詳細については この回答 を参照してください。

スレッドとプロセスの違い

Linuxに関する重要な質問です。ドキュメントには疑問が残るためです(たとえば、独自のPIDを持たないスレッドについて)。

注: この答え はLinuxスレッドを正確に説明します。

要するに、カーネルは「実行可能なエンティティ」、つまりrunおよびscheduledが可能なもののみを処理します。カーネルに関しては、これらのエンティティはプロセスと呼ばれます。スレッドは、(少なくとも)メモリ空間とシグナルハンドラを別のスレッドと共有する一種のプロセスです。

このようなすべてのプロセスには、システム全体で一意の識別子であるPID(プロセスID)があります。いわゆるスレッドの場合、TID(スレッドID)と呼ばれることもありますが、sysadmin(およびカーネル!)の観点からは、TIDとPIDは同じものです(同じ名前空間を共有します)。

その結果、canreniceそれぞれの「スレッド」には、ownPID1

reniceへのすべてのPIDを再帰的に検索する

すてきなプロセスの子孫(子またはスレッドグループ内)であるすべてのプロセス(「通常」または「スレッド」)のPIDを取得する必要があります。これは再帰的であるべきです(子供たちの子供を考えると)。

Anton Leontievの答えはそのためのヒントを与えます:/proc/$PID/task/のすべてのフォルダー名は、潜在的な子プロセスをリストするchildrenファイルを含むスレッドのPIDです。

ただし、これには再帰性がないため、これらを見つけるためのすばやく汚れたシェルスクリプトを次に示します。

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

プロセスPID 1234を再帰的に実行したい場合は、次のようにします。

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

1 POSIXに準拠するために、スレッド内でgetpid(2)を呼び出すと、この実行可能エンティティのシステム全体で一意のID(PID)がないので、 「スレッドグループ」内のメインプロセスのPID。代わりにgettid(2)を呼び出す必要があります。詳細は this answer を参照してください。

10
Totor

/proc/$PID/taskを使用して、特定のプロセスのすべてのスレッドを検索できるため、次のように使用できます

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

to renice all threads指定されたプロセスに属しています。

同じように/proc/$PID/task/$PID/childrenを使用して、すべての子プロセスを検索できます(または/proc/$PID/task/*/childrenが必要な場合は、すべての子プロセスを検索しますthreads特定のプロセスの)。

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

プロセスのPIDとスレッドIDをTIDまたはpsコマンドのLPWに書き込むことはありません。 sコマンドにはスレッドを表示するオプションがあり、topまたはhtopの下で、スレッドを切り替えてH文字で処理します。以前に@Totorによって伝えられたように、カーネル> 2.6の現在の実装であるNPTLでは、すべてのスレッドが同じpidを持っていますが、異なるtidを持っています。次の方法で、プロセスのすべてのスレッドを表示します。

$ ps -Ljf <pid>

これらのtidは/proc/<pid>/taskの下のディレクトリの名前であり、renice(1)が適用されたときにデフォルトの引数がpidであると言ってもpidに対しては、メインスレッドのみを放棄します(これは、setpriority(2)で記述されているLinux実装のバグです)。 tidとスレッドをレニシングします。 @Antonの答えが有効であるのはそのためです。

しかし、たいていの場合、望ましい結果を得る簡単な方法があります。これらすべてのスレッドは、グループリーダーのPIDである同じpgidを共有します。以下を発行することにより、pgidで再取得できます。

$ renice -g <pgid>

同じグループリーダーに依存する他のプロセスを再利用したくない場合は、@ Antonのレシピを使用する必要があります。

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

または:

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

また、同じグループの他のプロセスとして、やり直したいプロセス、つまり同じpgidを共有するプロセスを知りたい場合もあります。 ps(1)を使用できます。psではグループリーダーによるプロセスの選択は許可されていませんが、psを実行します。 pgid 1908のプロセスは、次のコマンドで表示されます。

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

またはawkでsedを使用する場合:

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

man renice によると(私の強調):

reniceは、1つ以上の実行中のプロセスのスケジューリング優先順位を変更します。最初の引数は、使用する優先度の値です。 他の引数は、プロセスID(デフォルト)、プロセスグループID、ユーザーID、またはユーザー名として解釈されます。 (...)

そして実際、 man pgrep は例として示しています:

例4:すべてのchromeプロセスをより適切に実行する:

$ renice +4 $(pgrep chrome)

これらによれば、renicepgrep-w | --lightweightスイッチを組み合わせて、すべてのスレッドを再許可することができます。 、 そのようです:

renice <priority> $(pgrep -w <process_name>)

そして再表示するすべての子プロセス

renice <priority> $(pgrep -P $(pgrep <process_name>))

また、-fスイッチをpgrepと共に使用して、プロセス名だけでなくコマンドライン全体を照会することもできます(完全一致である必要はありません)。

0
Marc.2377

Reniceを使用するときは、-p(プロセスID)ではなく-g(プロセスグループ)引数を使用することをお勧めします。 bash-fooがなくても同じことができます。

つまり.

(Sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>
0
user12042