Domanda

Ho un'applicazione che ha due thread.

Il primo (il thread principale) che acquisisce i dati utilizzando socket e aggiorna DataTables

Il secondo inserisce i DataTable nel database.

L'applicazione funziona correttamente ma quando si chiude, il thread principale termina la lettura dei dati e chiama il metodo Abort nel secondo thread, che potrebbe essere inserito nel database e ciò porta a dati incoerenti.

Attualmente sto usando la seguente soluzione per superare " interruzione durante l'inserimento "

EDIT: Dopo le potenti risposte ho cambiato il codice

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           
        }
     }
}
È stato utile?

Soluzione

Supponendo " chiama il metodo abort " significa interrompere il thread usando Thread.Abort. Non farlo .

Stai effettivamente bloccando l'app. Ci sono molti modi più puliti per farlo con i monitor.

Tuttavia, non dovresti ricevere dati incoerenti nel tuo DB quando l'app si arresta in modo anomalo, ecco perché hai transazioni DB con ACID proprietà.

MODIFICA MOLTO IMPORTANTE Hai detto: non usi le transazioni per motivi di performance e invece usi i mutex. Questo è SBAGLIATO su alcuni livelli. In primo luogo, le transazioni possono rendere più veloci determinate operazioni, ad esempio provare a inserire 10 righe in una tabella, riprovare all'interno di una transazione, la versione della transazione sarà più veloce. In secondo luogo, cosa succede quando / se l'app si arresta in modo anomalo, danneggi il tuo DB? Cosa succede quando sono in esecuzione più istanze della tua app? O mentre esegui rapporti sul tuo DB nell'analizzatore di query?

Altri suggerimenti

Finché entrambi i thread non sono contrassegnati come thread in background, l'app continuerà a funzionare fino all'uscita di entrambi i thread. Quindi, davvero, tutto ciò che devi fare è ottenere ogni thread separatamente per uscire in modo pulito. Nel caso del thread che scrive nel database, ciò può significare esaurire una coda produttore / consumatore e controllare una bandiera per uscire.

Ho mostrato una coda produttore / consumatore adatta qui - il lavoratore sarebbe semplicemente:

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...
}

Ecco un esempio completo basato su SizeQueue<> - nota che il processo non termina fino a quando il lettore e non sono usciti in modo pulito. Se non vuoi scaricare la coda (ad esempio, vuoi uscire prima e dimenticare qualsiasi lavoro in sospeso), allora va bene - aggiungi un flag extra (volatile) da qualche parte.

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");
    }
}

L'attesa di mutex dovrebbe comportare un timeout. L'anello esterno di ogni thread può verificare la presenza di un flag "per favore chiudi ora". Per chiudere, imposta il flag "per favore chiudi ora" per ogni thread, quindi usa "join" per attendere il completamento di ogni thread.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top