2009-06-28 13 views
5

Tengo una aplicación que tiene dos hilos.¿Completamente cerrada la aplicación de subprocesos múltiples?

El primero (el hilo principal) que captura los datos utilizando socket y actualizar DataTables

Los segundos insertos los DataTables en la base de datos.

La aplicación funciona bien pero cuando se cierra, el hilo principal termina de leer los datos y llama al método Anular en el segundo hilo, que puede estar insertándose en la base de datos y esto lleva a datos inconsistentes.

Actualmente estoy usando la siguiente solución para superar "abortar durante la inserción"

EDIT: Después de las respuestas potentes he cambiado el código

void MainThread() 
{ 
    while(Read()) 
    { 
     //Read Data through socket 
     try 
     { 
      //Wait on Mutex1 
      //Update Tables 
     } 
     finally 
     { 
      //Release Mutex1 
     } 
    } 
    _isrunning = false; 
    _secondThread.Join(); 
} 
void SecondThread() 
{ 
    while(_isrunning) 
    { 
     try 
     { 
      //Wait on Mutex1 
      //Insert Tables into Database using transactions 
     } 
     finally 
     { 
      //Release Mutex1   
     } 
    } 
} 
+5

Así que ... ¡no llame "Abortar"! No es una buena idea. Nunca. –

+1

Re su comentario "No quiero usar la transacción (por rendimiento), así que sin usar mutex e hilo.abortar la aplicación dará lugar a registros inconsistentes "- Tengo que secundar a Sam, eso es una locura. La mayoría de las bases de datos están totalmente optimizadas para las transacciones (de hecho, a menudo solo una reversión conlleva un costo adicional). No importa qué tan rápido su aplicación se puede ejecutar si se corrompe el estado. Primero hágalo funcionar con firmeza, luego (si es demasiado lento) perfile y encuentre los cuellos de botella de rendimiento real, y soluciónelos. No corrompa la base de datos ... –

+0

En particular, su mutex hace * * nada ** para ayudarlo cuando su ejecutor muera debido a factores externos ("proceso de eliminación", BSOD o (más probable) falla de energía). Solo una transacción está diseñada para proteger su inserción. ¿Por qué no le gustan? ? –

Respuesta

6

Suponiendo que "call abort method" significa abortar el hilo con Thread.Abort. Don't do that.

Estás bloqueando tu aplicación. Hay formas mucho más limpias de hacerlo con monitores.

No obstante, no debería recibir datos inconsistentes en su base de datos cuando su aplicación falla, es por eso que tiene transacciones de base de datos que tienen las propiedades ACID.

EDICIÓN MUY IMPORTANTE Dijiste: no usas transacciones por motivos de rendimiento, y en cambio usas mutexes. Esto es WRONG en bastantes niveles. En primer lugar, las transacciones pueden hacer que ciertas operaciones sean más rápidas, por ejemplo, intente insertar 10 filas en una tabla, inténtelo de nuevo dentro de una transacción, la versión de la transacción será más rápida. En segundo lugar, ¿qué sucede cuando/si tu aplicación falla, corrompes tu DB? ¿Qué ocurre cuando se ejecutan varias instancias de tu aplicación? ¿O mientras ejecuta informes contra su base de datos en el analizador de consultas?

+0

No quiero usar la transacción (por rendimiento), así que sin usar mutex y thread.abort la aplicación dará lugar a registros incoherentes –

+1

Después del comentario y su edición, me gustaría poder recomendar esto por segunda vez. –

+0

Tengo solo una instancia de mi aplicación, y no utilizo la transacción durante la inserción ya que el método de inserción se ejecuta cada segundo y no debería tomar más que el segundo –

8

Mientras ambos hilos no están marcados como fondo subprocesos, la aplicación seguirá ejecutándose hasta que ambos subprocesos salgan. Entonces, realmente, todo lo que necesita hacer es obtener cada hilo por separado para salir limpiamente. En el caso del hilo que escribe en la base de datos, esto puede significar agotar una cola de productor/consumidor y verificar que una bandera se cierre.

me mostraron una cola adecuada productor/consumidor here - el trabajador sólo sería:

void WriterLoop() { 
    SomeWorkItem item; // could be a `DataTable` or similar 
    while(queue.TryDequeue(out item)) { 
     // process item 
    } 
    // queue is empty and has been closed; all done, so exit... 
} 

Aquí hay un ejemplo completo basado en SizeQueue<> - Tenga en cuenta que el proceso no sale hasta que el lector y escritor han salido limpiamente. Si no desea tener que drenar la cola (es decir, desea salir antes y olvidarse de cualquier trabajo pendiente), agregue una bandera extra (volátil) en algún lugar.

static class Program { 
    static void Write(object message) { 
     Console.WriteLine(Thread.CurrentThread.Name + ": " + message); 
    } 
    static void Main() { 
     Thread.CurrentThread.Name = "Reader"; 
     Thread writer = new Thread(WriterLoop); 
     writer.Name = "Writer"; 
     var queue = new SizeQueue<int>(100); 
     writer.Start(queue); 
     // reader loop - note this can run parallel 
     // to the writer 
     for (int i = 0; i < 100; i++) { 
      if (i % 10 == 9) Write(i); 
      queue.Enqueue(i); 
      Thread.Sleep(5); // pretend it takes time 
     } 
     queue.Close(); 
     Write("exiting"); 
    } 
    static void WriterLoop(object state) { 
     var queue = (SizeQueue<int>)state; 
     int i; 
     while (queue.TryDequeue(out i)) { 
      if(i%10==9) Write(i); 
      Thread.Sleep(10); // pretend it takes time 
     } 
     Write("exiting"); 
    } 
} 
+0

Todavía una caída de la aplicación no debe causar corrupción DB ... –

+0

Es cierto que las actualizaciones individuales deben ser ACID, pero el bloqueo aquí se autoinflige al llamar a Abort. –

+0

hay un caso de borde donde es posible que desee infligir un bloqueo, por ej. en un servicio de ventana tiene un SLA que desea cumplir al cerrar una aplicación. Si por alguna razón una llamada está "bloqueada" en el DB debido al bloqueo y usted no puede señalizarla, puede considerar cancelar –

3

Su espera mutex debería implicar un tiempo de espera. El bucle externo de cada hilo puede verificar si hay un indicador de "cerrar ahora". Para cerrar, configure la bandera "por favor cierra ahora" para cada hilo, luego use "unir" para esperar a que termine cada hilo.

+0

maravillosa respuesta, simple y efectiva –

Cuestiones relacionadas