risposta-alla-domanda-sullo-sviluppo-web-bd.com

È possibile congelare temporaneamente un processo in linux?

Mi stavo chiedendo se esiste un modo per congelare qualsiasi processo per un certo periodo di tempo?

Quello che voglio dire è che: è possibile per un'applicazione (probabilmente in esecuzione come root) mettere in pausa l'esecuzione di un altro processo già in esecuzione (qualsiasi processo, sia la GUI che la riga di comando) e quindi riprenderlo in seguito? In altre parole, non voglio che determinati processi vengano pianificati dallo scheduler di Linux per un certo periodo di tempo.

52
Pal Szasz

Vedi qui

Ci sono due segnali che possono sospendere l'esecuzione di un processo. Uno è "grazioso" e uno è "forte".

Quello "aggraziato" è SIGTSTP, e il suo scopo è quello di "graziosamente" chiedere al processo, se ne ha voglia, di sospendere l'esecuzione fino a quando non riceve un SIGCONT. Nel caso di SIGTSTP, il processo può ignorare SIGTSTP e continuare comunque ad eseguirlo, quindi ciò richiede la cooperazione da un programma progettato per gestire SIGTSTP.

Quello "forte" è SIGSTOP e il suo scopo è quello di sospendere tutti i thread userspace associati a quel processo. È altrettanto impossibile che il processo ignori SIGSTOP poiché ignora SIGKILL (quest'ultimo uccide il processo con forza).

Per inviare un segnale arbitrario, compresi quelli menzionati qui, puoi usare programmi come kill, killall o pkill; oppure utilizzare la chiamata di sistema kill(2). Vedere le manpage del sistema operativo per i dettagli di piattaforma/architettura/versione dipendenti e gli errata relativi a uno dei precedenti. Nota che la parola "uccide" in tutti questi comandi e la syscall è un brutto malinteso. Questi comandi sono non progettati, esclusivamente, per terminare i processi. Loro possono farlo inviando alcuni dei segnali; ma i segnali possono anche essere utilizzati per funzionalità diverse dalla conclusione di un processo. Ad esempio, SIGSTOP sospende solo il processo, ed è solo uno dei numerosi segnali che possono essere inviati in questo modo.

Per aggiungere una condizione di ripresa automatica del processo dopo che è trascorso un certo periodo di tempo, sarà necessario utilizzare una sorta di processo di monitoraggio che rimane in esecuzione e imposta un timer per riattivare il processo di monitoraggio, che a sua volta chiama nuovamente kill(2) e invia il segnale SIGCONT al processo arrestato, al fine di richiedere al kernel di riprendere l'esecuzione. Si noti che Linux ha diversi meccanismi di temporizzazione con vari gradi di accuratezza e precisione; inoltre, se il tuo sistema è molto occupato, il tuo processo di monitoraggio potrebbe non essere svegliato fino a quando il suo timer non è scaduto, e quindi la sveglia potrebbe essere ritardata.

Se si dipende dalla precisione molto accurata della sospensione e dalla ripresa del processo sospeso, potrebbe essere necessario eseguire il programma di monitoraggio con autorizzazioni in tempo reale (vedere questa manpage su sched_setscheduler(2) per informazioni su come rendere il tuo processo in tempo reale). Puoi anche usare Timer ad alta risoluzione, una funzionalità del kernel Linux (che è disponibile solo se l'hardware ti fornisce supporto), in combinazione con la pianificazione in tempo reale, per ottenere molto precisione precisa, sub-millisecondo sul tempo, quindi sveglia e invia il segnale per riprendere il processo monitorato molto rapidamente.

Non hai indicato quali tecnologie sei disposto a utilizzare per implementarlo. Come minimo, avrai bisogno di almeno uno script di bash, anche se non sarai in grado di ottenere un tempismo a grana molto fine in questo modo. Ecco uno "script" di bash (non testato, quindi fai attenzione) che è solo una prova del concetto della tua query. Se hai bisogno di un tempismo preciso, dovrai scrivere un programma, probabilmente in C/C++ o un'altra lingua madre, e utilizzare la pianificazione e gli hrtimer in tempo reale.

#!/bin/bash
#This is the process you want to suspend.
screen -mdS child bash -c "cat /dev/urandom | base64"
#This is the process ID of the child process
THEPID=$(screen -list | grep child | cut -f1 -d'.' | sed 's/\W//g')
#Send SIGSTOP to the child process.
kill -SIGSTOP ${THEPID}
#Now it is suspended. This process will sleep for 10 seconds asynchronously, then resume the process.
screen -mdS monitor bash -c "sleep 10; kill -SIGCONT ${THEPID}"

Si noti che lo script terminerà e lo script di controllo terminerà, ma a causa di screen che controlla il processo di monitoraggio, continuerà a essere eseguito in background per 10 secondi (in base all'argomento passato a sleep) e quindi a riattivare e continuare il processo secondario . Ma questo avverrà molto tempo dopo che lo script di controllo è terminato. Se si desidera attendere in modo sincrono il tempo che trascorre, basta semplicemente omettere la seconda chiamata a screen e hardcodificare sleep and kill nello script di controllo.

È possibile verificare che il processo venga effettivamente sospeso eseguendo

screen -rS child

dopo aver avviato questo script. Non vedrai nulla sulla console. Quindi, dopo che il timer scade (10 secondi), invaderà lo schermo con i dati di base64 (caratteri casuali da 0-9 e A-F). Premi Ctrl + C per uscire.

80
allquixotic

Sì, puoi farlo inviando un STOP segnale a un processo per sospenderlo e quindi a CONT per continuare.

utilizzo:

kill -STOP <pid>

kill -CONT <pid>
13
user8228

Se hai una definizione sufficientemente libera di "freeze", puoi controllare il comando renice.

Renice consente di modificare la priorità di pianificazione dei processi in esecuzione.

Il normale processo Nice value è 0. L'aumento del valore Nice rende il processo più gradevole, come in "perché non vai prima tu". Mentre la riduzione del valore di Nizza rende un processo meno piacevole, come in "togliti di mezzo, ho fretta". Il range di valori Nice è compreso tra -20 e 19.

Chiunque può rendere i propri processi più belli. Solo la radice può rendere meno piacevole un processo o modificare la niceness di un altro utente.

Se si imposta un processo Nice value su 19, verrà eseguito solo quando nessun altro sul sistema lo desidera.

Ecco un esempio di esecuzione sulla mia linux box locale.

Usa ps -l e guarda la colonna NI per vedere un buon valore dei processi.

 -> ps -l 
 PPID CID UID FS C PRI NI ADDR SZ WCHAN TTY CMD 
 0 S 29190 402 31146 0 75 0 - 16547 wait pts/0 bash 
 0 T 29190 1105 402 0 75 0 - 23980 finish pts/0 vim 
 0 R 29190 794 402 0 76 0 - 15874 - pts/0 ps 
 

L'esecuzione di renice +10 sul processo vim fa sì che venga eseguito con una priorità più bassa.

 -> renice +10 -p 1105 
 1105: priorità vecchia 0, nuova priorità 10 
 
 -> ps -l 
 UID PID FS PPID C PRI NI ADDR SZ WCHAN TTY CMD 
 0 S 29190 402 31146 0 76 0 - 16547 wait pts/0 bash 
 0 T 29190 1105 402 0 95 10 - 23980 finish pts/0 vim 
 0 R 29190 1998 402 0 78 0 - 15874 - pts/0 ps 
 

Supponendo che si possa "congelare" il significato di "non disturbare nessun altro sul sistema" si potrebbe scrivere uno script come:

 renice 20 -p & ltpid di interesse> 
 sleep & ltcertain quantità di tempo> 
 renice 0 -p & ltpid di interesse> 

(ricordati di eseguirlo come root).


nota che ho preso alcune libertà con l'output ps -l di cui sopra per far apparire le colonne interessanti nelle piccole scatole blu :)

11
Maurice