代码之家  ›  专栏  ›  技术社区  ›  Ahmed

优雅地关闭多线程应用程序?

  •  5
  • Ahmed  · 技术社区  · 17 年前

    我有一个有两个线程的应用程序。

    第一个线程(主线程)使用套接字和更新数据表捕获数据

    第二种方法将数据表插入数据库。

    应用程序工作正常,但当它关闭时,主线程完成读取数据并在第二个线程中调用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           
            }
         }
    }
    
    3 回复  |  直到 17 年前
        1
  •  8
  •   Community Mohan Dere    9 年前

    只要两个线程都没有标记为后台线程,应用程序就会一直运行,直到两个线程都退出。所以,实际上,您需要做的就是让每个线程分别干净地退出。对于写入数据库的线程,这可能意味着耗尽生产者/消费者队列并检查要退出的标志。

    here -工人可能只是:

    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");
        }
    }
    
        2
  •  6
  •   Sam Saffron James Allen    17 年前

    假设“调用中止方法”意味着使用thread.abort中止线程。 Don't do that .

    你实际上是在破坏你的应用程序。有很多更干净的方法可以通过显示器来实现这一点。

    尽管如此,当你的应用程序崩溃时,你不应该在数据库中获得不一致的数据,这就是为什么你的数据库事务具有 ACID

    非常重要的编辑 您说过:出于性能原因,您不使用事务,而是使用互斥锁。这是 在相当多的层面上。首先,事务可以使某些操作更快,例如尝试在表中插入10行,在事务中重试,事务版本会更快。其次,当/如果你的应用程序崩溃,你会损坏你的数据库吗?当应用程序的多个实例正在运行时会发生什么情况?或者在查询分析器中对数据库运行报告时?

        3
  •  3
  •   Andrew    17 年前

    您的互斥等待应该包含一个超时。每个线程的外部循环都可以检查“请立即关闭”标志。要关闭,请为每个线程设置“请立即关闭”标志,然后使用“加入”等待每个线程完成。