既存commandのnice値を変更するときは、例示PIDを手入力しません。管理対象processを$!でbindし、PID・/proc start ticks・uid・comm・old niceを保存します。変更直前と復旧直前に同じtupleを再読し、PID再利用や別processならreniceを実行せず停止します。
対象processを$!でbindする
例ではnice 10で起動したsha256sumのPIDを$!から取得します。start timeは/proc/PID/statのfield 22に相当するticksをcommの閉じ括弧後から安全に読み、uid・commと結合します。niceを15から10へ戻す操作には権限が必要なため、承認済みroot shell以外では開始しません。
set -Eeuo pipefail
test "$EUID" -eq 0 || { printf 'STOP: exact nice rollback requires approved root shell\n' >&2; exit 20; }
read_identity() {
local pid=$1 stat_line rest uid comm
local -a fields
test -r "/proc/$pid/stat" && test -r "/proc/$pid/comm"
stat_line=$(<"/proc/$pid/stat")
rest=${stat_line##*) }
read -r -a fields <<< "$rest"
test "${#fields[@]}" -ge 20
uid=$(stat -c %u -- "/proc/$pid")
comm=$(<"/proc/$pid/comm")
printf '%s|%s|%s|%s\n' "$pid" "$uid" "${fields[19]}" "$comm"
}
priority_output=$(mktemp -p /srv/lab '.ittrip-139.sha256.XXXXXXXX')
nice --adjustment=10 sh -c 'exec sha256sum -- /srv/lab/large-image.iso' > "$priority_output" &
target_pid=$!
target_identity=$(read_identity "$target_pid")
old_nice=$(ps -o ni= -p "$target_pid" | tr -d ' ')
test "$old_nice" = 10
printf 'bound pid=%s identity=%s old_nice=%s\n' "$target_pid" "$target_identity" "$old_nice"
変更直前にidentityとold niceを再確認する
保存tupleと現在tuple、保存niceと現在niceが一致した一つのPIDだけを15へ変更します。ps -Cの複数候補やhardcoded 4242は使用しません。
approved_nice=15
test "$(read_identity "$target_pid")" = "$target_identity" || { printf 'STOP: PID identity changed before renice\n' >&2; exit 30; }
test "$(ps -o ni= -p "$target_pid" | tr -d ' ')" = "$old_nice"
renice --priority "$approved_nice" --pid "$target_pid"
test "$(read_identity "$target_pid")" = "$target_identity"
test "$(ps -o ni= -p "$target_pid" | tr -d ' ')" = "$approved_nice"
printf 'changed only bound pid=%s nice=%s->%s\n' "$target_pid" "$old_nice" "$approved_nice"
変更後も同じprocessか確認する
candidate PIDが同じ数字でもstart ticks・uid・commのどれかが違えばwrong/reused PIDとして停止します。変更後はnice=15をexact fieldとして確認し、別processへ追加操作しません。
# wrong/reused PIDならidentity gateでrenice前に停止する。
candidate_pid=$target_pid
candidate_identity=$(read_identity "$candidate_pid")
test "$candidate_identity" = "$target_identity" || { printf 'STOP: wrong or reused PID\n' >&2; exit 40; }
current_nice=$(ps -o ni= -p "$candidate_pid" | tr -d ' ')
test "$current_nice" = "$approved_nice"
ps -o pid=,uid=,ni=,lstart=,comm= -p "$candidate_pid"
printf 'identity_rebound=%s current_nice=%s\n' "$candidate_identity" "$current_nice"
保存したold niceへexact restoreする
復旧直前もidentityとcurrent nice=15を再bindし、固定値10ではなく保存済みold_niceへ戻します。復旧後に同じidentityとexact niceを再読して完了です。
test "$(read_identity "$target_pid")" = "$target_identity" || { printf 'STOP: PID identity changed before restore\n' >&2; exit 50; }
test "$(ps -o ni= -p "$target_pid" | tr -d ' ')" = "$approved_nice"
renice --priority "$old_nice" --pid "$target_pid"
test "$(read_identity "$target_pid")" = "$target_identity"
test "$(ps -o ni= -p "$target_pid" | tr -d ' ')" = "$old_nice"
printf 'restored exact baseline pid=%s nice=%s identity=%s\n' "$target_pid" "$old_nice" "$target_identity"
受入条件
wrong PID、終了済みPID、同じ番号を再利用したPIDではrenice呼出し前に停止します。clean fixtureでは対象processだけが10→15となり、同じPID/start/uid/commのまま15→保存値10へ戻ります。
nice値で解決できない問題
niceはCPU schedulerの相対priorityであり、CPU使用率上限、I/O priority、memory不足を直接制御しません。systemd serviceならunitのCPUWeight等を別途検討し、負niceやrealtime policyはさらに厳しい承認対象にします。
nice値の方向と権限境界を先に確認する
Linuxのnice値は数値が大きいほど通常のCPU scheduling優先度が低くなります。15へ変更する例は対象processを相対的に譲歩させる操作で、処理を高速化する指定ではありません。一般userはnice値を大きくする操作ができても、元の小さい値へ戻す操作には権限が必要な場合があります。そのためexact rollbackを受入条件にする本例では、開始前に承認済みroot shellを要求し、権限不足を途中で発見して変更だけが残る状態を避けます。
短命processの終了と成果物を別々に判定する
PIDは再利用され得るため、reniceの前後とrestore前にPID、UID、/procのstarttime、command名を束ねたidentityを比較します。一方、対象が自然終了してidentityを読めなくなった場合は、別PIDへ操作を続けず停止します。restore後はwaitで同じ子processの終了statusを取得し、sha256sumの成果物が1行だけで、64桁のdigestと承認済み入力pathを含むことを別に確認します。nice値が戻ったことと処理結果が正しいことは別の合格条件です。
set +e
wait "$target_pid"
worker_status=$?
set -e
test "$worker_status" -eq 0
test -s "$priority_output"
test "$(wc -l < "$priority_output")" -eq 1
result_line=$(sed -n '1p' -- "$priority_output")
result_hash=${result_line%%[[:space:]]*}
case "$result_hash" in (''|*[!0-9a-fA-F]*) printf 'STOP: invalid SHA256 output
' >&2; exit 60;; esac
test "${#result_hash}" -eq 64
case "$result_line" in (*' /srv/lab/large-image.iso') ;; (*) printf 'STOP: output path mismatch
' >&2; exit 61;; esac
printf 'worker_status=%s sha256=%s evidence=%s
' "$worker_status" "$result_hash" "$priority_output"
nice以外が支配する負荷は別の指標へ切り分ける
niceが調整するのは通常classのCPU schedulingにおける相対的な扱いです。CPU quotaやcgroupのCPUWeight、real-time policy、I/O wait、memory pressure、storage帯域が律速なら、nice値だけを反復変更しても期待した効果は得られません。変更前後で対象identity、nice値、elapsed time、CPU使用率、I/O待ちを同じ観測窓に保存し、効果がなければ元のnice値へ戻して原因調査へ切り替えます。他processを一括指定したり、名前一致だけで対象を広げたりしないでください。
公式情報・参考資料
コマンド実行優先度の構文と制約は、本文末の一次資料と対象環境のlocal helpで照合します。コマンド実行優先度の記事確認日は2026年7月17日で、版が異なる場合はoption、default、終了statusの差を先に確認してください。

コメント