Pregunta

Tengo una aplicación que tiene dos hilos.

El primero (el hilo principal) que captura los datos usando el socket y actualiza DataTables

El segundo inserta las tablas de datos 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 Abort en el segundo hilo, que puede estar insertando en la base de datos y esto conduce a datos inconsistentes.

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

EDITAR: Después de las poderosas respuestas cambié 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           
        }
     }
}
¿Fue útil?

Solución

Suponiendo " llame al método de cancelación " significa abortar el hilo usando Thread.Abort. No hagas eso .

Está bloqueando efectivamente su aplicación. Hay muchas maneras más limpias de hacer esto con los monitores.

Sin embargo, no deberías obtener datos inconsistentes en tu base de datos cuando tu aplicación falla, por eso tienes transacciones de base de datos que tienen el ACID propiedades.

EDICIÓN MUY IMPORTANTE Usted dijo: no usa transacciones por razones de rendimiento, y en su lugar usa mutexes. Esto es INCORRECTO en bastantes niveles. En primer lugar, las transacciones pueden acelerar ciertas operaciones, por ejemplo, intente insertar 10 filas en una tabla, intente nuevamente dentro de una transacción, la versión de la transacción será más rápida. En segundo lugar, ¿qué sucede cuando / si su aplicación falla, corrompe su base de datos? ¿Qué sucede cuando se ejecutan varias instancias de su aplicación? ¿O mientras ejecuta informes en su DB en el analizador de consultas?

Otros consejos

Mientras ambos hilos no estén marcados como hilos de fondo, la aplicación seguirá ejecutándose hasta que salgan ambos hilos. 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 marcar una bandera para salir.

Mostré una cola adecuada de productor / consumidor aquí : el trabajador simplemente estarí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 se cierra hasta que el lector y el escritor hayan salido limpiamente. Si no desea tener que agotar la cola (es decir, desea salir antes y olvidarse de cualquier trabajo pendiente), entonces bien: agregue una bandera adicional (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");
    }
}

Su espera de mutex debe implicar un tiempo de espera. El bucle externo de cada subproceso puede verificar si hay un indicador de "cierra ahora". Para cerrar, configure el indicador 'cerrar ahora' para cada hilo, luego use 'unirse' para esperar a que termine cada hilo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top