Question

J'ai une application qui a deux threads.

Le premier (le thread principal) qui capture les données à l'aide de socket et met à jour les DataTables

La seconde insère les DataTables dans la base de données.

L’application fonctionne correctement, mais lorsqu’elle se ferme, le thread principal termine la lecture des données et appelle la méthode Abort dans le second thread, ce qui peut être une insertion dans la base de données, ce qui entraîne des données incohérentes.

J'utilise actuellement la solution suivante pour surmonter & "Abandonner lors de l'insertion" & ";

EDIT: Après les réponses puissantes, j'ai changé le code

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           
        }
     }
}
Était-ce utile?

La solution

En supposant & "appelez la méthode d'abandon &"; signifie abandonner le thread à l'aide de Thread.Abort. Ne faites pas cela .

Vous écrasez effectivement votre application. Il existe de nombreuses façons plus propres de le faire avec les moniteurs.

Néanmoins, vous ne devriez pas recevoir de données incohérentes dans votre base de données lorsque votre application se bloque, c'est pourquoi vous avez des transactions de base de données dont le ACID , propriétés.

MODIFICATION TRÈS IMPORTANT Vous avez dit: vous n'utilisez pas de transactions pour des raisons de performances, mais utilisez plutôt des mutex. C'est FAUX à plusieurs niveaux. Premièrement, les transactions peuvent accélérer certaines opérations. Par exemple, essayez d'insérer 10 lignes dans une table, essayez à nouveau dans une transaction, la version de la transaction sera plus rapide. Deuxièmement, que se passe-t-il lorsque / si votre application se bloque, corrompez-vous votre base de données? Que se passe-t-il lorsque plusieurs instances de votre application sont en cours d'exécution? Ou alors que vous exécutez des rapports sur votre base de données dans l’analyseur de requêtes?

Autres conseils

Tant que les deux threads ne sont pas marqués en tant que threads d'arrière-plan, l'application continuera à fonctionner jusqu'à la sortie des deux threads. Donc, en réalité, tout ce que vous avez à faire est d’obtenir chaque thread séparément pour qu’il se termine proprement. Dans le cas du thread qui écrit dans la base de données, cela peut signifier l’épuisement de la file d’attente d’un producteur / consommateur et la vérification d’un indicateur de sortie.

J'ai montré une file d'attente appropriée de producteurs / consommateurs ici - le travailleur serait simplement:

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

Voici un exemple complet basé sur SizeQueue<> - notez que le processus ne se termine pas tant que le lecteur et le rédacteur ne sont pas sortis proprement. Si vous ne souhaitez pas vider la file d’attente (c’est-à-dire que vous souhaitez quitter plus tôt et oublier tout travail en attente), ajoutez un indicateur supplémentaire (volatil) quelque part.

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

Votre attente mutex devrait impliquer un délai d'attente. La boucle extérieure de chaque fil peut vérifier si le drapeau "fermez maintenant maintenant" apparaît. Pour arrêter, activez le drapeau "s'il vous plaît fermer maintenant" pour chaque thread, puis utilisez "join" pour attendre que chaque thread se termine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top