2009-07-24 9 views
6

Tengo un programa en modo consola que usa SQLite3 para mantener un archivo de base de datos. Se tarda un tiempo en ejecutarse, pero debería ser seguro cancelarlo en cualquier momento, suponiendo que ocurra la escritura de la base de datos. (Esto es todo bajo Windows)TerminateProcess vs Ctrl + C

¿Es más seguro, desde el punto de un programa en ejecución, para golpear CtrlC en la consola de tener otro TerminateProcess llamada del programa en él?

Me he dado cuenta de que puedo dañar la base de datos si se invoca TerminateProcess, supongo que es porque el programa no tiene la posibilidad de finalizar las escrituras. Supongo que CtrlC es mejor, porque el programa recibe una señal y se termina a sí mismo, en lugar de que el sistema operativo lo mate.

Tenga en cuenta que el programa no maneja la señal (a menos que SQLite lo haga); Estoy hablando de los mecanismos predeterminados incorporados de los ejecutables Win32 para manejar la señal CtrlC.

Aclarar/simplificar el cuestionable dado que esta escritura solo ha ejecutado:

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

Durante esta escritura, se TerminateProcess comportamiento diferente del de CtrlC?

Respuesta

5

Todos estos son argumentos convincentes, pero la única manera de saberlo con certeza es probarlo. Así que escribí un programa simple que asigna un buffer de 1GB, le asigna algunos datos y luego lo escribe en un archivo usando un solo fwrite().He intentado varios métodos para obtener la escritura de "corruptos" los datos (que estaba esperando un archivo truncado, específicamente):

  • Calling TerminateProcess (a través de la función matanza de Perl y Win32 :: :: Proceso de muertes)
  • golpear CtrlC
  • El uso de "Terminar proceso" del Administrador de tareas
  • Usando Proceso "Kill Process" del Explorador de

Nada detendría la escritura en todos los casos, el archivo tenía el tamaño correcto y tenía los datos correctos. Y aunque la "muerte" ocurriría instantáneamente, el proceso se demoraría hasta que la escritura se hubiera completado.

Parece concluyente de que no hay diferencia entre TerminateProcess y CtrlC desde un punto de vista- una vez que las aperturas de escritura de E/S, parece garantizado para completar (salvo los cortes de energía).

+0

Muy interesante, supongo que la operación IO se completa independientemente, ya que simplemente no tiene sentido detenerla, ¿qué podría hacer sino conducir a la corrupción? Debe ser otra forma de bloquear TerminateProcess oculto en algún lugar. Cosas interesantes. Gracias. – Gavin

+1

Sospecho que TerminateProcess no puede matar el proceso de forma segura mientras realiza un syscall: el contexto del subproceso en esa etapa se encuentra en el espacio del kernel, y al matarlo a la fuerza puede haber pérdidas de recursos del sistema. El sistema operativo probablemente instala ganchos para todos los hilos del proceso que se están ejecutando actualmente en el espacio del kernel, lo que mata al hilo cuando intenta regresar de syscall. – pmdj

0

SQLite afirma ser atómico, incluso durante los cortes de energía, consulte http://www.sqlite.org/atomiccommit.html.

La única excepción es que algunos sistemas de disco informan que la escritura se realizó correctamente antes de que los datos se escriban en los discos, es decir, los datos están en la memoria caché o el sistema operativo está mintiendo a SQLite. Consulte http://www.sqlite.org/lockingv3.html, sección 6.0 Cómo dañar sus archivos de base de datos.

Procesos terminados must stop all running threads and complete pending I/O operations before they exit. Se debe garantizar la integridad de los datos, siempre que el proceso no se haya bloqueado.

+0

"La única diferencia a este respecto entre Ctrl-C y TerminateProcess es cómo se ha escrito la aplicación para manejar cualquiera de estos eventos". ¿Es esta conjetura o tiene alguna prueba para respaldarla? – arolson101

+0

El enlace que dio Manuel parece ser autoritativo. Aparentemente, hice una suposición incorrecta sobre la terminación; debe estar pendiente de E/S que mantiene la tarea abierta, en lugar de que el programador intercepte la llamada finalizada. Edité mi respuesta para reflejar esto. –

1

Su aplicación tiene la oportunidad de manejar CtrlC y Ctrlrotura, como golpes o señales (depende de la configuración) clave, lo que significa que la aplicación tiene la oportunidad de hacer una salida limpia, estas serían una forma mucho más suave de finalizar un proceso, lo que le permitiría un poco más de tiempo de ejecución si nada más.

TerminateProcess es más una patada en los dientes, la aplicación no puede manejar esto, viene del kernel, y si la aplicación pudiera manejarlo, esto crearía toda clase de problemas con los procesos 'inacabables' que cuelgan su TerminateProcess controlador y se niega a salir.

Como lo entiendo tan pronto como se invoca TerminateProcess en el proceso, no puede ejecutar más código, es decir, no se limpia, no se apaga, simplemente termina, no se puede manejar, simplemente no tendría sentido si pudiera, no desde una perspectiva de seguridad.

Excelente artículo del proyecto de código aquí en el manejo de ventanas señales de consola:

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

implementar algunas de las señales más arriba que el manejo podría asegurar que las escrituras de base de datos tienen la oportunidad de completar antes de salir del programa, en lugar de posiblemente dejándolo al azar.

Puede bloquear TerminateProcess, pero su programación 'no es realmente' educada ', es más como la programación del kit raíz, he visto un buen artículo sobre esto en rootkit.com así que busque allí' Invencibilidad del proceso 'una vez que tenga el proceso invencible, podría en su propio momento cerrar después de recibir tal 'petición', y realizar cualquier limpieza antes de hnad, pero esto sin duda es un hack.

Me parece sin embargo que el CtrlC comportamiento que está viendo actualmente es debido que no inmediatamente poner fin al proceso en ejecución.

0

creo para sus propósitos, es más seguro utilizar CtrlC. Esto causará que se envíe una señal al programa. Si el programa no maneja la señal, terminará en el acto.

TerminateProcess finaliza por la fuerza el proceso y cualquier subproceso secundario.

De MSDN:

TerminateProcess función termina el proceso especificado y todos sus hilos. ... Observaciones

La función TerminateProcess se utiliza para causar un proceso incondicionalmente a salir. El estado de los datos globales mantenido por las bibliotecas de vínculos dinámicos (DLL) puede verse comprometido si se utiliza TerminateProcess en lugar de ExitProcess.

TerminateProcess inicia la terminación y lo devuelve inmediatamente. Esto detiene la ejecución de todos los hilos dentro del proceso y solicita la cancelación de todas las E/S pendientes. El proceso finalizado no puede salir hasta que se hayan completado o cancelado todas las E/S pendientes.

Un proceso no puede evitar que se termine.

Hay formas en que un proceso bloquea TerminateProcess, pero dudo que SQLite3 lo haga.

+0

Su artículo parece indicar que no hay diferencia, pero usted dice que es más seguro usar CTRL + C. Recuerde, estamos hablando de un programa no específicamente escrito para manejar señales. ¿Hay alguna razón por la que dices que es más seguro usar CTRL + C? – arolson101

+0

CTRL + C no forzaría la terminación del proceso y subprocesos secundarios, solo indicaría que se apagara. Si no se maneja, entonces simplemente sale. TerminateProcess puede causar daños en los datos globales como dice en MSDN. En su solución, usted declara que nada detendría la escritura; eso es porque incluso TerminateProcess no lo terminará si hay E/S ("El proceso finalizado no puede salir hasta que todas las E/S pendientes hayan sido completadas o canceladas"). Eso fue en MSDN también. – Manuel