Вопрос

У меня есть приложение, которое имеет два потока.

Первый (основной поток), который собирает данные с помощью сокета и обновляет таблицы данных

Второй вставляет таблицы данных в базу данных.

Приложение работает нормально, но когда оно закрывается, основной поток завершает чтение данных и вызывает метод Abort во втором потоке, который может быть вставлен в базу данных, и это приводит к несогласованным данным.

В настоящее время я использую следующее решение для преодоления "прерывания во время вставки"

Редактировать:После убедительных ответов я изменил код

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           
        }
     }
}
Это было полезно?

Решение

Предполагая, что "метод прерывания вызова" означает прерывание потока с использованием Thread .Прервать. Не делай этого.

Вы фактически приводите к сбою своего приложения.Есть множество более чистых способов сделать это с мониторами.

Тем не менее, вы не должны получать противоречивые данные в своей базе данных при сбое вашего приложения, поэтому у вас есть транзакции БД, которые имеют КИСЛОТА свойства.

ОЧЕНЬ ВАЖНАЯ ПРАВКА Ты сказал:вы не используете транзакции по соображениям производительности, а вместо этого используете мьютексы.Это НЕПРАВИЛЬНО на довольно многих уровнях.Во-первых, транзакции могут ускорить определенные операции, например, попробуйте вставить 10 строк в таблицу, повторите попытку в рамках транзакции, версия транзакции будет быстрее.Во-вторых, что происходит, когда / если ваше приложение выходит из строя, вы повреждаете свою базу данных?Что происходит, когда запущено несколько экземпляров вашего приложения?Или во время выполнения отчетов по вашей базе данных в query analyzer?

Другие советы

Пока оба потока не помечены как фоновые потоки, приложение будет продолжать работать до тех пор, пока оба потока не завершатся.Так что на самом деле, все, что вам нужно сделать, это заставить каждый поток по отдельности завершаться чисто.В случае потока, который выполняет запись в базу данных, это может означать исчерпание очереди производителя / потребителя и проверку флага на выход.

Я показал подходящую очередь производителя / потребителя здесь - рабочий просто был бы:

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

Вот полный пример, основанный на SizeQueue<> - обратите внимание, что процесс не завершается до тех пор, пока считыватель и писатель вышел чисто.Если вы не хотите, чтобы вам приходилось истощать очередь (т.е.вы хотите выйти раньше и забыть о любой ожидающей работе), тогда прекрасно - добавьте где-нибудь дополнительный (изменчивый) флаг.

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

Ваше ожидание мьютекса должно включать тайм-аут.Внешний цикл каждого потока может проверять наличие флага "пожалуйста, закройте сейчас".Чтобы завершить работу, установите флаг "пожалуйста, закройте сейчас" для каждого потока, затем используйте "присоединиться", чтобы дождаться завершения каждого потока.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top