Come posso interrompere un processo ed essere sicuro che il PID non sia stato riutilizzato


40

Supponiamo, ad esempio, di avere uno script di shell simile a:

longrunningthing &
p=$!
echo Killing longrunningthing on PID $p in 24 hours
sleep 86400
echo Time up!
kill $p

Dovrebbe fare il trucco, no? Solo che il processo potrebbe essere terminato in anticipo e il suo PID potrebbe essere stato riciclato, il che significa che un lavoro innocente ottiene invece una bomba nella sua coda di segnale. In pratica questo forse conta, ma mi preoccupa comunque. Fare l'hacking di tutto ciò che è morto da solo, o mantenere / rimuovere il suo PID sull'FS farebbe, ma sto pensando alla situazione generica qui.


3
Ti assicuri che se il tuo processo mirato muore, uccide il suo assassino nel processo.
Mikeserv,

2
Usa le killallcorrispondenze sul nome, quindi almeno stai uccidendo un processo con lo stesso nome di longrunningthing. Supponendo che ne avrai solo una in esecuzione alla volta.
LawrenceC,

8
È possibile salvare l'ora di inizio del processo originale e, prima di uccidere, verificare che l'ora di inizio del processo con quel pid corrisponda a ciò che è stato salvato. La coppia pid, start-time è un identificatore univoco per i processi in Linux.
Bakuriu,

1
Posso chiederti perché ne hai bisogno? Qual è la cosa fondamentale che stai cercando di ottenere? (qualcosa che funziona continuamente ma viene reimpostato ogni 24 ore?)
Olivier Dulac il

2
@mikeserv Un processo non può garantire che accadrà qualcosa in caso di morte.
Kasperd,

Risposte:


29

La cosa migliore sarebbe usare il timeoutcomando se ce l'hai che è pensato per quello:

timeout 86400 cmd

L'attuale implementazione (8.23) GNU funziona almeno usando alarm()o equivalente durante l'attesa del processo figlio. Non sembra essere guardia dal SIGALRMconsegnato tra waitpid()rinvio e di timeoutuscire (annullando efficacemente che allarme ). Durante quella piccola finestra, timeoutpuò persino scrivere messaggi su stderr (per esempio se il bambino ha scaricato un core) che allargherebbe ulteriormente quella finestra di corsa (indefinitamente se stderr è un tubo pieno per esempio).

Personalmente posso convivere con questa limitazione (che probabilmente verrà risolta in una versione futura). timeoutpresterà inoltre particolare attenzione a segnalare lo stato di uscita corretto, gestire altri casi angolari (come SIGALRM bloccato / ignorato all'avvio, gestire altri segnali ...) meglio di quanto probabilmente si farebbe a mano.

Come approssimazione, potresti scriverlo perlcome:

perl -MPOSIX -e '
  $p = fork();
  die "fork: $!\n" unless defined($p);
  if ($p) {
    $SIG{ALRM} = sub {
      kill "TERM", $p;
      exit 124;
    };
    alarm(86400);
    wait;
    exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
  } else {exec @ARGV}' cmd

C'è un timelimitcomando su http://devel.ringlet.net/sysutils/timelimit/ (precede GNU timeoutdi qualche mese).

 timelimit -t 86400 cmd

Quello utilizza un alarm()meccanismo simile ma installa un gestore SIGCHLD(ignorando i bambini arrestati) per rilevare la morte del bambino. Annulla anche l'allarme prima dell'esecuzione waitpid()(che non annulla la consegna di SIGALRMse era in sospeso, ma il modo in cui è scritto, non riesco a vedere che è un problema) e uccide prima di chiamare waitpid()(quindi non posso uccidere un pid riutilizzato ).

netpipes ha anche un timelimitcomando. Che uno precede tutti gli altri di decenni, adotta un altro approccio, ma non funziona correttamente per i comandi arrestati e restituisce uno 1stato di uscita al timeout.

Come risposta più diretta alla tua domanda, potresti fare qualcosa del tipo:

if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
  kill "$p"
fi

Cioè, controlla che il processo sia ancora un nostro figlio. Ancora una volta, c'è una piccola finestra di gara (tra il psrecupero dello stato di quel processo e l' killuccisione) durante la quale il processo potrebbe morire e il suo pid può essere riutilizzato da un altro processo.

Con alcune conchiglie ( zsh, bash, mksh), è possibile passare le specifiche di lavoro, invece di pid.

cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status

Funziona solo se si genera solo un lavoro in background (altrimenti non è sempre possibile ottenere il jobpec giusto in modo affidabile).

Se questo è un problema, basta avviare una nuova istanza della shell:

bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd

Ciò funziona perché la shell rimuove il lavoro dalla tabella dei lavori quando il bambino muore. Qui, non dovrebbe esserci alcuna finestra di gara poiché al momento della chiamata della shell kill(), o il segnale SIGCHLD non è stato gestito e il pid non può essere riutilizzato (poiché non è stato atteso), oppure è stato gestito e il il lavoro è stato rimosso dalla tabella dei processi (e killsegnalerebbe un errore). bash's kill, almeno blocchi SIGCHLD prima di accedere la sua tabella di lavoro per espandere la %e lo sblocca dopo il kill().

Un'altra opzione per evitare che quel sleepprocesso rimanga in sospeso anche dopo che cmdè morto, con basho ksh93è usare una pipa con read -tinvece di sleep:

{
  {
    cmd 4>&1 >&3 3>&- &
    printf '%d\n.' "$!"
  } | {
    read p
    read -t 86400 || kill "$p"
  }
} 3>&1

Quella ha ancora le condizioni di gara e perdi lo stato di uscita del comando. Presuppone anche cmdche non chiuda il suo fd 4.

Potresti provare a implementare una soluzione priva di gare perlcome:

perl -MPOSIX -e '
   $p = fork();
   die "fork: $!\n" unless defined($p);
   if ($p) {
     $SIG{CHLD} = sub {
       $ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
       sigprocmask(SIG_BLOCK, $ss, $oss);
       waitpid($p,WNOHANG);
       exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
           unless $? == -1;
       sigprocmask(SIG_UNBLOCK, $oss);
     };
     $SIG{ALRM} = sub {
       kill "TERM", $p;
       exit 124;
     };
     alarm(86400);
     pause while 1;
   } else {exec @ARGV}' cmd args...

(anche se dovrebbe essere migliorato per gestire altri tipi di custodie angolari).

Un altro metodo senza gara potrebbe essere l'utilizzo di gruppi di processi:

set -m
((sleep 86400; kill 0) & exec cmd)

Tuttavia, notare che l'utilizzo di gruppi di processi può avere effetti collaterali se è presente l'I / O su un dispositivo terminale. Ha l'ulteriore vantaggio di uccidere tutti gli altri processi extra generati da cmd.


4
Perché non menzionare prima il metodo migliore?
deltab,

2
@deltab: timeoutnon è portatile, la risposta menzionava prima una soluzione portatile.
cuonglm,

1
@deltab: fornisce informazioni su come funzionano le cose e in particolare su come l'approccio del "buon senso" può fallire (Stephane preferisce insegnare a pescare per primo, cosa che mi piace). Ci si aspetta che legga l'intera risposta
Olivier Dulac il

@Stephane: per "ottenere il jobpec giusto non è sempre possibile in modo affidabile": non puoi prima contare l'output di jobse poi sapere che (come è la tua shell, in cui hai il controllo su ciò che accade dopo) il prossimo background lavoro sarà N + 1? [poi puoi salvare N e successivamente uccidere% N + 1])
Olivier Dulac il

1
@OlivierDulac, che supponeva che nessun lavoro passato fosse terminato quando ne avvii uno nuovo (le shell riutilizzano i numeri dei lavori).
Stéphane Chazelas,

28

In generale, non puoi. Tutte le risposte fornite finora sono euristiche errate. C'è solo un caso in cui è possibile utilizzare in sicurezza il pid per inviare segnali: quando il processo di destinazione è un figlio diretto del processo che invierà il segnale e il genitore non lo ha ancora atteso. In questo caso, anche se è uscito, il pid è riservato (questo è un "processo di zombi") fino a quando il genitore non lo attende. Non sono a conoscenza di alcun modo per farlo in modo pulito con la shell.

Un modo alternativo sicuro per uccidere i processi è avviarli con un set tty di controllo su uno pseudo-terminale per il quale possiedi il lato master. È quindi possibile inviare segnali tramite il terminale, ad esempio scrivendo il carattere per SIGTERMo SIGQUITsopra il pty.

Ancora un altro modo più conveniente per gli script è quello di utilizzare una screensessione denominata e inviare comandi alla sessione dello schermo per terminarla. Questo processo si svolge su un socket pipe o unix denominato in base alla sessione dello schermo, che non verrà automaticamente riutilizzato se si sceglie un nome univoco sicuro.


4
Non riesco a capire perché questo non possa essere fatto con le conchiglie. Ho dato diverse soluzioni.
Stéphane Chazelas,

3
Potresti fornire una spiegazione e una sorta di discussione quantitativa sui finestrini della gara e altri inconvenienti? Senza di ciò, "Tutte le risposte finora fornite sono euristiche errate" è un confronto inutilmente inutile senza alcun vantaggio.
peterph,

3
@peterph: in generale, qualsiasi uso di un pid è una razza TOCTOU - non importa come controlli se si riferisce ancora allo stesso processo a cui ti aspetti che faccia riferimento, potrebbe smettere di fare riferimento a quel processo e fare riferimento ad alcuni nuovi elaborare nell'intervallo prima di utilizzarlo (invio del segnale). L'unico modo per impedirlo è quello di poter bloccare la liberazione / riutilizzo del pid e l'unico processo che può farlo è il genitore diretto.
R ..

2
@ StéphaneChazelas: in che modo si impedisce alla shell di attendere un processo in background che è terminato? Se riesci a farlo, il problema è facilmente risolvibile nel caso in cui OP abbia bisogno.
R ..

5
@peterph: "La finestra della gara è piccola" non è una soluzione. E la rarità della gara dipende dall'assegnazione sequenziale del pid. I bug che causano eventi molto brutti una volta all'anno sono molto peggio dei bug che accadono continuamente perché sono praticamente impossibili da diagnosticare e correggere.
R ..

10
  1. All'avvio del processo, salvare l'ora di inizio:

    longrunningthing &
    p=$!
    stime=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    echo "Killing longrunningthing on PID $p in 24 hours"
    sleep 86400
    echo Time up!
    
  2. Prima di provare a terminare il processo fermalo (questo non è veramente essenziale, ma è un modo per evitare le condizioni di gara: se interrompi il processo, il pid non può essere riutilizzato)

    kill -s STOP "$p"
    
  3. Verifica che il processo con quel PID abbia lo stesso orario di inizio e, in caso affermativo, interrompilo, altrimenti lascia che il processo continui:

    cur=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    if [ "$cur" = "$stime" ]
    then
        # Okay, we can kill that process
        kill "$p"
    else
        # PID was reused. Better unblock the process!
        echo "long running task already completed!"
        kill -s CONT "$p"
    fi
    

Questo funziona perché può esserci un solo processo con lo stesso PID e l' ora di inizio su un dato sistema operativo.

L'arresto del processo durante il controllo rende le condizioni di gara non problematiche. Ovviamente questo ha il problema che, alcuni processi casuali potrebbero essere fermati per alcuni millisecondi. A seconda del tipo di processo, questo può o meno essere un problema.


Personalmente avrei semplicemente usato Python e psutilche gestisce automaticamente il riutilizzo del PID:

import time

import psutil

# note: it would be better if you were able to avoid using
#       shell=True here.
proc = psutil.Process('longrunningtask', shell=True)
time.sleep(86400)

# PID reuse handled by the library, no need to worry.
proc.terminate()   # or: proc.kill()

Regole Python in UNIX ... Non sono sicuro del motivo per cui più risposte non iniziano qui poiché sono sicuro che la maggior parte dei sistemi non ne proibisce l'utilizzo.
Mr. Mascaro,

Ho usato uno schema simile (usando l'ora di inizio) prima, ma le tue abilità di scripting sh sono più ordinate delle mie! Grazie.
FJL,

Ciò significa che potenzialmente stai interrompendo il processo sbagliato. Si noti che il ps -o start=formato cambia da 18:12 a Jan26 dopo un po '. Attenzione anche alle modifiche dell'ora legale. Se su Linux, probabilmente preferirai TZ=UTC0 ps -o lstart=.
Stéphane Chazelas,

@ StéphaneChazelas Sì, ma dopo lo lasci continuare. Ho detto esplicitamente: a seconda del tipo di attività che quel processo sta eseguendo potresti avere qualche problema a fermarlo per alcuni millisecondi. Grazie per la lstart
segnalazione

Nota che (a meno che il tuo sistema non limiti il ​​numero di processi per utente), è facile per chiunque riempire la tabella dei processi con zombi. Una volta rimasti solo 3 pid disponibili, è facile per chiunque avviare centinaia di processi diversi con lo stesso pid in un solo secondo. Quindi, a rigor di termini, il tuo "può esserci un solo processo con lo stesso PID e l'ora di inizio su un dato sistema operativo" non è necessariamente vero.
Stéphane Chazelas,

7

Su un sistema Linux puoi assicurarti che un pid non verrà riutilizzato mantenendo in vita il suo spazio dei nomi pid. Questo può essere fatto tramite il /proc/$pid/ns/pidfile.

  • man namespaces -

    Associare il montaggio (vedere mount(2)) uno dei file in questa directory in un'altra posizione nel filesystem mantiene vivo lo spazio dei nomi corrispondente del processo specificato da pid anche se tutti i processi attualmente nello spazio dei nomi terminano.

    L'apertura di uno dei file in questa directory (o di un file associato a uno di questi file) restituisce un handle di file per lo spazio dei nomi corrispondente del processo specificato da pid. Finché questo descrittore di file rimane aperto, lo spazio dei nomi rimarrà attivo, anche se tutti i processi nello spazio dei nomi terminano. Il descrittore di file può essere passato a setns(2).

È possibile isolare un gruppo di processi, praticamente qualsiasi numero di processi, assegnandone il nome init.

  • man pid_namespaces -

    Il primo processo creato in un nuovo spazio dei nomi (ad esempio, il processo creato utilizzando clone(2) con il flag CLONE_NEWPID o il primo figlio creato da un processo dopo una chiamata unshare(2)all'utilizzo del flag CLONE_NEWPID ) ha il PID 1 ed è il initprocesso per lo spazio dei nomi ( vedi init(1)) . Un processo figlio orfano all'interno dello spazio dei nomi verrà reintegrato in questo processo anziché init(1) (a meno che uno degli antenati del bambino nello stesso spazio dei nomi PID impiegasse il comando prctl(2) PR_SET_CHILD_SUBREAPER per contrassegnare se stesso come il mietitore dei processi discendenti orfani) .

    Se il initprocesso di uno spazio dei nomi PID termina, il kernel termina tutti i processi nello spazio dei nomi tramite un segnale SIGKILL . Questo comportamento riflette il fatto che il initprocesso è essenziale per il corretto funzionamento di uno spazio dei nomi PID .

Il util-linuxpacchetto fornisce molti strumenti utili per manipolare gli spazi dei nomi. Ad esempio, unsharetuttavia, se non sono già stati predisposti i diritti in uno spazio dei nomi utente, saranno necessari i diritti di superutente:

unshare -fp sh -c 'n=
    echo "PID = $$"
    until   [ "$((n+=1))" -gt 5 ]
    do      while   sleep 1
            do      date
            done    >>log 2>/dev/null   &
    done;   sleep 5' >log
cat log; sleep 2
echo 2 secs later...
tail -n1 log

Se non hai predisposto uno spazio dei nomi utente, puoi comunque eseguire in modo sicuro comandi arbitrari eliminando immediatamente i privilegi. Il runusercomando è un altro binario (non setuid) fornito dal util-linuxpacchetto e che lo incorpora potrebbe apparire come:

sudo unshare -fp runuser -u "$USER" -- sh -c '...'

...e così via.

Nell'esempio sopra due interruttori vengono passati unshare(1)la --forkbandiera che rende il Richiamato sh -cprocesso il primo figlio creato e garantisce la sua initstato e la --pidbandiera che istruisce unshare(1)per creare uno spazio pid.

Il sh -cprocesso genera cinque shell secondarie in background, ognuna un whileciclo inifinite che continuerà ad aggiungere l'output datealla fine di logfintanto che sleep 1restituisce true. Dopo aver generato questi processi, shchiama sleepper altri 5 secondi, quindi termina.

Vale forse la pena notare che se la -fbandiera non venisse utilizzata nessuno dei whileloop con sfondo terminerebbe, ma con esso ...

PRODUZIONE:

PID = 1
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
2 secs later...
Mon Jan 26 19:17:48 PST 2015

Risposta interessante che sembra essere robusta. Probabilmente un po 'eccessivo per l'uso di base, ma vale la pena pensarci.
Uriel,

Non vedo come o perché mantenere in vita uno spazio dei nomi PID impedisca il riutilizzo di un PID. La stessa manpage che citi - Fintanto che questo descrittore di file rimane aperto, lo spazio dei nomi rimarrà in vita, anche se tutti i processi nello spazio dei nomi terminano - suggerisce che i processi potrebbero ancora terminare (e quindi presumibilmente avere l'ID del processo riciclato). Cosa c'entra mantenere vivo lo spazio dei nomi PID con la prevenzione del riutilizzo del PID stesso da parte di un altro processo?
davmac,

5

Considera di migliorare il tuo longrunningthingcomportamento, un po 'più simile a un demone. Ad esempio, puoi farlo creare un pidfile che consentirà almeno un controllo limitato del processo. Esistono diversi modi per farlo senza modificare il file binario originale, tutti implicando un wrapper. Per esempio:

  1. uno script wrapper semplice che avvierà il processo richiesto in background (con reindirizzamento dell'output facoltativo), scriverà il PID di questo processo in un file, quindi attenderà che il processo termini (usando wait) e rimuova il file. Se durante l'attesa il processo viene ucciso ad esempio da qualcosa del genere

    kill $(cat pidfile)
    

    il wrapper si assicurerà che il pidfile sia rimosso.

  2. un wrapper monitor, che metterà il proprio PID da qualche parte e catturerà (e risponderà) ai segnali inviati ad esso. Esempio semplice:

    #!/bin/bash
    p=0
    trap killit USR1

    killit () {
        printf "USR1 caught, killing %s\n" "$p"
        kill -9 $p
    }

    printf "monitor $$ is waiting\n"
    therealstuff &
    p=%1
    wait $p
    printf "monitor exiting\n"

Ora, come hanno sottolineato @R .. e @ StéphaneChazelas, questi approcci hanno spesso una condizione di competizione da qualche parte o impongono una limitazione al numero di processi che puoi generare. Inoltre, non gestisce i casi in cui si longrunningthingpossono staccare may fork e i bambini (che probabilmente non è quale fosse il problema nella domanda originale).

Con i kernel Linux recenti (leggi un paio di anni), questo può essere ben trattato usando i cgroups , vale a dire il freezer - che, suppongo, è quello che usano alcuni moderni sistemi init Linux.


Grazie e a tutti. Sto leggendo tutto adesso. Il punto longrunningthingè che non hai alcun controllo su ciò che è. Ho anche dato un esempio di script di shell perché spiegava il problema. Mi piacciono le tue e tutte le altre soluzioni creative qui, ma se stai usando Linux / bash c'è un "timeout" incorporato per questo. Suppongo che dovrei ottenere la fonte per quello e vedere come lo fa!
FJL,

@FJL, nontimeout è incorporato nella shell. Ci sono state varie implementazioni di un comando per Linux, una è stata recentemente (2008) aggiunta ai coreutils GNU (quindi non specifici per Linux), ed è quello che la maggior parte delle distribuzioni Linux usa al giorno d'oggi. timeout
Stéphane Chazelas,

@ Stéphane - Grazie - Successivamente ho trovato un riferimento ai coreutils GNU. Possono essere portatili, ma se non si trovano nel sistema di base non possono essere invocati. Sono più interessato a sapere come funziona, anche se noto il tuo commento altrove suggerendo che non è affidabile al 100%. Dato il modo in cui questa discussione è andata, non mi sorprende!
FJL,

1

Se stai utilizzando Linux (e alcuni altri * nix), puoi verificare se il processo che intendi uccidere è ancora usato e che la riga di comando corrisponde al tuo lungo processo. Qualcosa di simile a :

echo Time up!
grep -q longrunningthing /proc/$p/cmdline 2>/dev/null
if [ $? -eq 0 ]
then
  kill $p
fi

Un'alternativa può essere quella di verificare per quanto tempo è in corso il processo che si intende uccidere, con qualcosa del genere ps -p $p -o etime=. Potresti farlo da solo estraendo queste informazioni /proc/$p/stat, ma questo sarebbe difficile (il tempo è misurato in jiffies e dovrai usare anche il tempo di attività del sistema /proc/stat).

In ogni caso, di solito non è possibile garantire che il processo non venga sostituito dopo il controllo e prima di ucciderlo.


Non è ancora corretto perché non si sbarazza delle condizioni di gara.
Strcat,

@strcat In effetti, nessuna garanzia di successo, ma la maggior parte degli script non si preoccupa nemmeno di fare questo controllo e uccide senza mezzi termini un cat pidfilerisultato. Non riesco a ricordare un modo pulito per farlo solo in shell. La risposta allo spazio dei nomi proposta sembra interessante ...
Uriel,

-1

Questa è in realtà un'ottima domanda.

Il modo per determinare l'unicità del processo è guardare (a) dove si trova nella memoria; e (b) cosa contiene quella memoria. Per essere precisi, vogliamo sapere dove si trova in memoria il testo del programma per l'invocazione iniziale, perché sappiamo che l'area di testo di ogni thread occuperà una diversa posizione in memoria. Se il processo termina e ne viene avviato un altro con lo stesso pid, il testo del programma per il nuovo processo non occuperà lo stesso posto in memoria e non conterrà le stesse informazioni.

Quindi, subito dopo aver avviato il processo, esegui md5sum /proc/[pid]/mapse salva il risultato. Più tardi, quando vuoi terminare il processo, fai un altro md5sum e confrontalo. Se corrisponde, quindi uccidi il pid. Altrimenti no.

per vederlo da solo, lancia due identiche shell bash. Esaminali /proc/[pid]/mapsper e scoprirai che sono diversi. Perché? Perché anche se è lo stesso programma, occupano posizioni diverse nella memoria e gli indirizzi del loro stack sono diversi. Quindi, se il tuo processo muore e il suo PID viene riutilizzato, anche con lo stesso comando che viene riavviato con gli stessi argomenti , il file "maps" sarà diverso e saprai che non hai a che fare con il processo originale.

Vedi: proc man page per i dettagli.

Si noti che il file /proc/[pid]/statcontiene già tutte le informazioni che altri poster hanno menzionato nelle loro risposte: età del processo, pid principale, ecc. Questo file contiene sia informazioni statiche che dinamiche, quindi se si preferisce utilizzare questo file come base di confronto, quindi all'avvio longrunningthing, è necessario estrarre i seguenti campi statici dal statfile e salvarli per il confronto in un secondo momento:

pid, nome file, pid del genitore, ID gruppo di processi, terminale di controllo, processo temporale avviato dopo l'avvio del sistema, dimensione del set di residenti, indirizzo di inizio dello stack,

nel complesso, quanto sopra identifica in modo univoco il processo, e questo rappresenta un altro modo di procedere. In realtà non si poteva far altro che "pid" e "processo temporale avviato dopo l'avvio del sistema" con un alto grado di sicurezza. Basta estrarre questi campi dal statfile e salvarlo da qualche parte all'avvio del processo. Più tardi, prima di ucciderlo, estrailo di nuovo e confronta. Se corrispondono, allora sei sicuro che stai guardando il processo originale.


1
Questo generalmente non funzionerà come /proc/[pid]/mapsmodifiche nel tempo man mano che viene allocata memoria aggiuntiva o lo stack cresce o vengono creati nuovi file ... E cosa significa immediatamente dopo l'avvio ? Dopo che tutte le librerie sono state modificate? Come lo determini?
Stéphane Chazelas,

Sto facendo un test ora sul mio sistema con due processi, uno un'app java e l'altro un server cfengine. Ogni 15 minuti lo faccio md5sumsui loro file delle mappe. Lo lascerò correre per un giorno o due e riferirò qui con i risultati.
Michael Martinez,

@ StéphaneChazelas: controllo le mie due procedure da 16 ore e non c'è stato alcun cambiamento nel md5sum
Michael Martinez,

-1

Un altro modo sarebbe quello di verificare l'età del processo prima di ucciderlo. In questo modo, puoi assicurarti di non uccidere un processo che non viene generato in meno di 24 ore. È possibile aggiungere una ifcondizione basata su quella prima di terminare il processo.

if [[ $(ps -p $p -o etime=) =~ 1-. ]] ; then
    kill $p
fi

Questa ifcondizione verificherà se l'ID processo $pè inferiore a 24 ore (86400 secondi).

PS: - Il comando ps -p $p -o etime=avrà il formato<no.of days>-HH:MM:SS


Il mtimeof /proc/$pnon ha nulla a che fare con l'ora di inizio del processo.
Stéphane Chazelas,

Grazie @ StéphaneChazelas. Hai ragione. Ho modificato la risposta per cambiare la ifcondizione. Non esitate a commentare se il suo buggy.
Sree,

-3

Quello che faccio è, dopo aver terminato il processo, farlo di nuovo. Ogni volta che lo faccio, la risposta ritorna "nessun processo"

allenb   12084  5473  0 08:12 pts/4    00:00:00 man man
allenb@allenb-P7812 ~ $ kill -9 12084
allenb@allenb-P7812 ~ $ kill -9 12084
bash: kill: (12084) - No such process
allenb@allenb-P7812 ~ $ 

Non potrebbe essere più semplice e lo faccio da anni senza problemi.


Questo sta rispondendo alla domanda "come posso peggiorare le cose", non al "come posso ripararlo".
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.