
Gestione ''classica'' dei processi su GNU/Linux
Dalle basi teoriche, mediante i comandi maggiormente utilizzati, ecco come lanciare, instradare, scovare ed, eventualmente, “uccidere” un processo
(pagina 1 di 2)
Per controllare efficacemente il proprio
sistema è indispensabile comprendere
fino in fondo il funzionamento dei processi,
ovvero le singole esecuzioni di
quelle entità che, nel loro complesso e spesso in
concerto, erogano tutta la moltitudine di servizi
con cui siamo abituati ad operare. Per chiarirci meglio
le idee richiameremo alcuni concetti di teoria
delle macchine e di Unix. Ogni volta che il sistema
operativo, ovvero una sua parte e, quindi, un eseguibile che più o meno
volontariamente abbiamo invocato, agisce, vengono manipolate in memoria
determinate strutture dati proprie del processo. Alcune strutture
contengono
costrutti utili alle sincronizzazioni e ai controlli, altre istruzioni
da eseguire,
altre ancora una porzione di memoria in cui ospitare i risultati delle
operazioni.
Ciò vale per ogni processo. Esaminando le cose ad un livello ancora più
basso, ogni processo può essere ulteriormente suddiviso in uno o più
thread
che rappresentano una sequenza di operazioni da processare nell’ordine
in
cui sono lette. Questa concezione seriale del calcolo, derivata dalla
progettazione
dei calcolatori, è stata superata e in alcuni contesti, come quelli dei
processori più moderni, è possibile processare contemporaneamente più
thread.
I processori in grado di far ciò vengono definiti multithread; per
essere
sfruttati in tal senso è nondimeno necessario
che tutti i livelli di software coinvolti siano
stati concepiti appositamente per lo scopo.
Comprendere ciò aiuta a definire meglio alcuni
fenomeni altrimenti oscuri, come le cadute
prestazionali rispetto le attese osservate
adoperando sistemi operativi di concezione
obsoleta ma ospitati su macchine di realizzazione
più moderna, ed è inoltre utile per
fugare la confusione che spesso nasce fra i termini multithread e
multitask.
Mentre il primo termine fa riferimento, quindi, a principi di
parallelismo e a
gestione contemporanea del calcolo principalmente dal punto di vista
hardware,
il secondo si riferisce alla capacità software di interrompere una
serie
di operazioni per gestirne un’altra, quindi riprendere la prima serie
di operazioni,
dividendo così la potenza di calcolo a “fette di tempo”, secondo questo
modello, per un numero sterminato di sequenze operative, quindi anche
di
processi. La gestione dei tempi di calcolo e di attesa è controllata
dal kernel
mediante opportuni algoritmi di scheduling. Mettiamo momentaneamente
da parte questi concetti, ci saranno utili per meglio comprendere
quanto segue,
per i nostri scopi non sarà necessario, comunque, andare ulteriormente
a fondo nell’anatomia dei processi, ma basterà considerare che
osservando
le cose ad un livello più alto, perché il sistema possa gestire tutti i
processi,
è necessario che, in memoria, venga mantenuta una mappa globale dei
processi
attivi. Al livello più alto di astrazione, ovvero a livello
dell’utente, ogni processo attivo può essere distinto dagli altri
processi attivi tramite il PID
(acronimo di Process Identifier), che lo identifica univocamente. Il
PID è
un numero che viene assegnato ad ogni processo alla sua nascita e che
lo
accompagna durante tutta la sua esistenza. Se due processi nascono in
istanti
successivi il più giovane, seguendo una numerazione incrementale, avrà
il
PID immediatamente seguente a quello del predecessore, a patto che il
PID
da assegnare sia libero, perché i PID, pur essendo numerati in
sequenza,
devono tener conto dei limiti delle attuali architetture. Essendo
impossibile
gestire numeri “grandi quanto si vuole” potrà capitare che il PID da
assegnare
richieda un numero più grande di quello gestibile, in questo caso,
semplicemente,
l’assegnazione ricomincia dall’inizio, sfruttando e riassegnando
però solo PID dei processi che nel frattempo sono morti. Conoscendo il
PID sono possibili tutta una serie di operazioni che altrimenti
risulterebbero
quantomeno difficilmente praticabili. Spesso, per intervenire su un
processo,
è necessario conoscere questo numero da passare come argomento.
 |
Il contenuto della directory /proc |
 |
Output del comando nice. In basso la console “fi glio” |
Gli stati dei processi
Da “dormiente” a “zombie”. Cosa significa?
Un processo può essere runnable o running, vale a dire
pronto per essere eseguito o in esecuzione, oppure sleeping,
ovvero in attesa di poter operare su una risorsa come
il disco o di un evento come l’input da tastiera; in questo
stato il processo non consuma risorse di calcolo. Un processo
può divenire stopped, cioè interrotto da uno specifico
segnale e quindi in attesa del segnale di continuazione,
oppure zombie, cioè in attesa di essere correttamente
terminato.
La directory proc
Da qui il kernel comunica con l’esterno.
Una delle cose fondamentali da imparare è la diagnostica
legata ai processi. Esiste una gestione molto raffinata del
carico di calcolo sotto GNU/Linux. L’utente più smaliziato
può monitorare ogni esecuzione indagandola e, se necessario,
instradandola. Per i curiosi consigliamo di dare un rapido
sguardo al percorso di file system /proc. Non è una vera
directory appartenente al disco ma una directory virtuale
che “fotografa” i processi in esecuzione e colleziona alcune
informazioni sulla macchina.
Il Kernel e i processi
Quando il kernel gestisce un processo opera su diverse informazioni. La
mappa
dello spazio di indirizzamento del processo, i dati riguardanti le
risorse da questo
utilizzate, la sua maschera dei segnali, il proprietario,
rispettivamente l’user
UID e il gruppo GID, nonché le loro varianti estese EUID e EGID,
utilizzate
per meglio modulare le politiche di proprietà e i relativi permessi.
Oltre a questo
il kernel gestisce lo stato corrente del processo (dormiente, bloccato,
eseguibile,
ecc.) , informazione intimamente legata alle necessità di schedulazione.
Inoltre, considera la priorità di esecuzione del processo (il valore di
niceness)
ovvero la priorità di scheduling di un processo, questo è il parametro
principale
utilizzabile per influenzare la quantità di tempo-CPU resa disponibile
per il processo. L’algoritmo che presiede lo scheduling tiene inoltre
conto del
tempo già speso per il processo e del tempo di attesa per l’esecuzione.
Il valore
di niceness può essere incrementato dall’utente per rendere il processo
meno
“affamato” di risorse ma mai decrementato. L’utente root può
incrementare o
decrementare il valore di niceness di qualsiasi processo. Un processo
neonato
eredita il valore di niceness del padre. Tipicamente, perché un nuovo
processo
possa nascere, il processo che lo genera dovrà effettuare un fork,
generando una copia esatta di se stesso da differenziare in seguito, di
norma la niceness
non viene però modificata in questa fase. Al boot vengono avviati
numerosi
processi, sotto GNU/Linux, a meno di particolari personalizzazioni, il
primo
processo generalmente è init che assumerà PID 1 e avvierà gli altri
processi.
È necessario intervenire sul niceness di un processo in pochi casi, gli
algoritmi
di scheduling sono di consueto molto efficienti. Quasi sempre potremo
fidarci
in tal senso del sistema. Può, comunque, essere una buona idea
intervenire
sul valore di niceness di un processo se questo, in modo inatteso,
assorbe una
quantità tale di risorse da rendere difficoltoso il controllo della
macchina ma,
nonostante ciò, non desideriamo comunque fermarne l’esecuzione.
 |
Il monitor dei processi Gnome. Povero di informazioni, meglio il terminale! |
Monitorare i processi con top
Facile da usare, semplice da capire e affidabilissimo.
Top dice tutto
Il comando top è sicuramente tra
i tool migliori per osservare i principali
processi in esecuzione e campionarne,
a breve intervalli di tempo, alcuni parametri,
come, fra gli altri, percentuale di utilizzo per
le CPU e la memoria, comando e utente di
lancio e, molto importante, il PID associato.
Comandi di gestione
Top può filtrare i processi in base
agli utenti proprietari, basta
premere u. Inoltre, premendo il tasto r è
possibile effettuare il renice, quindi impostare
una nuova priorità per il processo. Attraverso
la pressione di k è poi, invece, possibile
uccidere un processo specificandone il PID.
Controllo a tempo
Top effettua i controlli a intervalli
di tempo. Per stabilire ogni quanto
tempo deve farlo premiamo s o d. Inoltre,
è meglio evitare intervalli troppo brevi, sia
perché appesantiscono il PC, sia perché qualora
la schermata cambi troppo rapidamente
il risultato risulterebbe di difficile lettura.
Processi in background
Sono in esecuzione, ma non si vedono
Come utile curiosità, ricordiamo anche l’operando & che,
accodato a un comando, lo esegue in background restituendo
il controllo alla console, e il comando nohup che lancia il
comando argomento immune dalla disconnessione consentendo
così di affrancare il processo figlio dalla sorte che
toccherà al processo padre qualora esso dovesse morire,
quindi il processo immune da disconnessione, alla morte
del padre, invece di cadere, diventerà figlio del PID 1.
Un processo “Gentile”
I comandi nice e renice per stabilire le priorità
Il valore di niceness di un processo può essere impostato
al lancio utilizzando il comando nice e l’eseguibile come
argomento. Il comando renice può essere invece utilizzato,
passando come argomento il PID, per reimpostare il valore
di niceness di un processo attivo. I due comandi nice e renice
potrebbero variare nell’uso degli argomenti da sistema a
sistema, quindi è buona norma, prima di lanciarli, richiamare
sempre le pagine man relative.
Ci sono anche ps, uptime e pstree
Per avere informazioni rapide, è possibile usare questi tre comandi, efficienti e molto potenti.
Processi correnti
ps -ef visualizza l’elenco dei
processi attivi segnalando, fra
l’altro, il processo padre (PPID), da cui deriva
quello corrente e il relativo PID. Inoltre, fornisce
informazioni sul tempo di lancio e sul
comando invocato per avviare il processo.
Vista ad albero
Il comando pstree restituisce una
particolare rappresentazione
ad albero dei processi in esecuzione e delle
relazioni padre-figlio. Passandogli un PID
come argomento, l’albero verrà visualizzato
partendo da questo.
Dati temporali
uptime visualizza il tempo trascorso
dall’ultimo avvio e una statistica
del peso totale di calcolo in rapporto a
quello ottenuto uno, cinque e quindici minuti
prima del suo lancio. Spesso questi valori
sono espressi come frazione decimale.
Kill e i suoi segnali
Quando desideriamo interrompere, uccidere o far riprendere un processo
in
esecuzione, dobbiamo lanciargli un segnale. Il comando kill, al
contrario di
quanto lasciato supporre dal nome molto specifico, può inviare ai
processi, con
opportuni argomenti, diversi tipi di segnali per ottenere vari
risultati. Il segnale di default comporta una richiesta di terminazione
software. Ci sono processi
che non reagiranno al comando di terminazione software perché alcuni
segnali
possono essere ignorati, momentaneamente bloccati ovvero accodati in
attesa
di essere sbloccati, oppure “catturati” e quindi gestiti dal processo
qualora
quello in questione abbia al suo interno istruzioni per gestire quei
segnali. In
tutti gli altri casi sarà il kernel ad effettuare azioni volte a
soddisfare le richieste
effettuate. Il comando man signal fornisce un elenco dei segnali che è
possibile
inviare. Se un processo non è morto e desideriamo ucciderlo, possiamo
provare
con il comando kill passando prima del PID argomento -9, così facendo
invieremo
un segnale di terminazione che non può essere bloccato o catturato.
Ricerche specifiche con pidof e pgrep
Gli operatori appositamente studiati per rispondere a queste esigenze.
Basta il “nome”
pidof identifica il PID di un processo di cui si conosce
solo il nome di lancio, ovvero la riga di comando con cui
è stato eseguito, restituendo il valore numerico che ci consente di
operare attraverso gli altri tool previsti per il controllo dei processi.
Ricerche mirate
pgrep consente di effettuare diverse ricerche sui PID, sui
gruppi che li hanno lanciati, sugli orari di esecuzione e
su molto altro ancora, ad esempio pgrep -u user elenca tutti i PID
associati all’utente user fornendo una lista dei relativi PID.
Assassini di massa
Quando più processi sono fuori controllo, possiamo terminarli insieme.
Fuori tutti!
Conoscendo il comando che ha generato più processi, è
possibile ucciderli tutti con killall. Questo si rivela utile
nel caso in cui, ad esempio, il browser stia generando un elevato
numero di istanze e non desideriamo chiuderle tutte una ad una.
Scova e uccide
pkill effettua ricerche uguali a pgrep, ma uccide i processi
trovati. Ricordiamo che solo root può agire su tutti
i processi. Il comando pkill può risultare utile quando, ad esempio,
bisogna interrompere, in un sol colpo, tutti i processi di un utente.