2009-07-24 17 views
6

Ho un programma di console-mode che utilizza SQLite3 per mantenere un file di database. Ci vuole un po 'per essere eseguito, ma dovrebbe essere sicuro in qualsiasi momento di annullarlo, assumendo che le scritture del database avvengano. (Questo è tutto sotto Windows)TerminateProcess vs Ctrl + C

E 'più sicuro, dal punto di un programma in esecuzione, per colpire CtrlC nella console piuttosto che avere un altro TerminateProcess chiamata del programma su di esso?

Ho notato che posso ottenere il danneggiamento del database se viene chiamato TerminateProcess. Presumo che ciò sia dovuto al fatto che il programma non ha la possibilità di terminare le scritture. La mia ipotesi è che CtrlC è meglio, perché il programma ottiene un segnale e termina se stesso, piuttosto che il sistema operativo che lo uccide.

Nota che il programma in realtà non gestisce il segnale (a meno che non lo fa SQLite); Sto parlando dei meccanismi di default built-in di eseguibili Win32 per gestire il CtrlC segnale.

Per chiarire/semplificare la Question- dato che questo articolo ha appena eseguito:

fwrite(buf, 1024*1024, 1, stream); 

Durante questo articolo, sarà TerminateProcess comportarsi in modo diverso da CtrlC?

risposta

5

Tutti questi argomenti sono convincenti, ma l'unico modo per sapere con certezza è provarlo. Così ho scritto un semplice programma che assegna un buffer da 1 GB, assegna alcuni dati ad esso, quindi lo scrive su un file usando un singolo fwrite().Ho provato diversi metodi per ottenere la scrittura per "corrotti" i dati (mi aspettavo un file troncato, nello specifico):

  • Calling TerminateProcess (tramite la funzione di uccidere Perl e Win32 :: Process :: Uccidere)
  • colpire CtrlC
  • Utilizzando "Termina processo" di Task manager
  • usando il processo "processo di Kill" di Explorer

Niente avrebbe fermato la scrittura in ogni caso, il file aveva le dimensioni corrette e aveva i dati corretti. E anche se il "Kill" si sarebbe verificato all'istante, il processo sarebbe durato fino al completamento della scrittura.

Sembra conclusiva che non v'è alcuna differenza tra TerminateProcess e CtrlC da un punto di I/O di vista- una volta che inizia la scrittura, sembra garantito per completare (salvo interruzioni di corrente).

+0

Molto interessante, suppongo che l'operazione di I/O sia completata a prescindere, in quanto semplicemente non ha senso fermarlo, cosa potrebbe fare diversamente da portare alla corruzione. Deve essere un altro modo per bloccare TerminateProcess nascosto da qualche parte. Roba interessante Grazie. – Gavin

+1

Sospetto che TerminateProcess non possa uccidere il processo in modo sicuro mentre sta eseguendo un syscall: il contesto del thread in quel momento si trova nello spazio del kernel e la sua uccisione forzata potrebbe far perdere risorse di sistema. Il sistema operativo probabilmente installa ganci per tutti i thread del processo attualmente in esecuzione nello spazio del kernel che interrompono il thread quando tenta di tornare da syscall. – pmdj

0

SQLite afferma di essere atomico, anche in caso di interruzioni di corrente, vedere http://www.sqlite.org/atomiccommit.html.

L'unica eccezione è rappresentata dal fatto che alcuni sistemi disco segnalano che la scrittura è avvenuta correttamente prima che i dati vengano effettivamente scritti sui dischi del disco, ovvero i dati si trovano nella cache del disco o il sistema operativo giace su SQLite. Vedere http://www.sqlite.org/lockingv3.html, sezione 6.0 Come danneggiare i file del database.

Processi terminati must stop all running threads and complete pending I/O operations before they exit. L'integrità dei dati dovrebbe essere garantita, a condizione che il processo non si sia arrestato in modo anomalo.

+0

"L'unica differenza in questo senso tra un Ctrl-C e un TerminateProcess è come l'applicazione è stata scritta per gestire uno di questi eventi." Questa congettura o avete qualche prova per eseguirne il backup? – arolson101

+0

Il link che Manuel ha dato sembra essere autorevole. Apparentemente ho fatto un'ipotesi errata sulla cessazione; deve essere in attesa di I/O che mantiene l'attività aperta, piuttosto che il programmatore che intercetta la chiamata terminata. Ho modificato la mia risposta per riflettere questo. –

1

L'applicazione ha la possibilità di gestire CtrlC e CtrlPausa, come battute o segnali (dipende dalla configurazione), il che significa che l'applicazione ha la possibilità di fare un'uscita pulita, questi sarebbero un modo molto più morbido per terminare un processo, permettendo un po 'più di tempo di esecuzione se non altro.

TerminateProcess è più un calcio ai denti, l'applicazione non può gestirlo, viene dal kernel e, se l'applicazione è in grado di gestirlo, questo creerebbe tutti i tipi di problemi con i processi "un killable" che pendono il loro TerminateProcess gestore e rifiuto di uscire.

Come ho capito non appena TerminateProcess viene chiamato nel processo, non può eseguire più codice questo, non ripulire, non spegnere, è appena finito, non puoi gestirlo, semplicemente non avrebbe senso se potessi, non dal punto di vista della sicurezza.

Ottimo articolo del progetto di codice qui sulla gestione finestre segnali di console:

http://www.codeproject.com/KB/winsdk/console_event_handling.aspx

attuazione di alcune del segnale sopra di voi la gestione potrebbe garantire che le scritture di database hanno la possibilità di completare prima che il programma viene chiuso, piuttosto che forse lasciandolo al caso.

È possibile bloccare TerminateProcess, ma la sua programmazione 'non molto' educata ', è più simile alla programmazione del root kit, ho visto un buon articolo su rootkit.com quindi cerca' Process Invincibility 'una volta che hai il processo invincibile, potrebbe, a suo tempo, spegnersi dopo aver ricevuto una simile "richiesta" ed eseguire qualsiasi ripulitura prima di hnad, ma questo è certamente un trucco.

Mi sembra però che il CtrlC comportamento che si sta vedendo è dovuto non immediatamente porre fine al processo in esecuzione.

0

Credo per i vostri scopi, è più sicuro da usare CtrlC. Ciò causerà la terminazione di un segnale inviato al programma. Se il programma non gestisce il segnale, terminerà sul posto.

TerminateProcess interrompe forzatamente il processo e qualsiasi thread figlio.

Da MSDN:

TerminateProcess funzione termina il processo specificato e tutti i suoi fili. ... Note

La funzione TerminateProcess viene utilizzata per provocare in modo incondizionato un processo all'uscita . Lo stato dei dati globali gestito da librerie a collegamento dinamico (DLL) potrebbe essere compromesso se si utilizza TerminateProcess anziché ExitProcess.

TerminateProcess avvia la risoluzione e restituisce immediatamente. Questo arresta l'esecuzione di tutti i thread all'interno del processo e richiede l'annullamento di tutti gli I/O in sospeso. Il processo terminato non può essere terminato finché tutti gli I/O in sospeso non sono stati completati o annullati.

Un processo non può impedire a se stesso di terminare .

Ci sono modi per un processo di bloccare TerminateProcess, ma dubito che SQLite3 lo farà.

+0

Il tuo articolo sembra affermare che non c'è alcuna differenza, ma tu dici che è più sicuro usare CTRL + C. Ricorda, stiamo parlando di un programma non specificamente scritto per gestire i segnali. C'è un motivo per cui dici che è più sicuro usare CTRL + C? – arolson101

+0

CTRL + C non imporrà la terminazione del processo e dei thread figlio, ma gli direbbe solo di spegnersi. Se non è gestito, allora esce. TerminateProcess può causare il danneggiamento dei dati globali come indicato su MSDN. Nella tua soluzione, dichiari che nulla fermerebbe la scrittura; questo perché persino TerminateProcess non lo terminerà se c'è un I/O ("Il processo terminato non può essere terminato fino a quando tutti gli I/O in attesa sono stati completati o annullati."). Anche in MSDN. – Manuel