2009-06-28 83 views
5

我有一个应用程序有两个线程。优雅地关闭多线程应用程序?

,使用插座和更新数据表

第二插件的数据表到数据库中捕获的数据的第一个(主线程)。

该应用程序工作正常,但当它关闭时,主线程完成读取数据并在第二个线程中调用Abort方法,该方法可能会插入到数据库中,并导致数据不一致。

目前我使用下面的解决方案来克服

EDIT“插入过程中中止”: 强大的答案后,我改变了代码

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   
     } 
    } 
} 
+5

所以..不要叫“中止”!这不是一个好主意。永远。 – 2009-06-28 09:51:00

+1

重新评论“我不想使用事务(为了性能),所以不使用互斥和线程。放弃应用程序会导致不一致的记录“ - 我不得不第二个Sam;这太疯狂了,大多数数据库都针对交易进行了全面优化(事实上,通常只有回滚会带来额外的成本)。可以运行,如果它损坏的状态。让它稳健地工作,然后(如果它太慢)分析它,并找到实际的性能瓶颈,并修复它们。不要破坏数据库... – 2009-06-28 11:45:14

+0

特别是,你的互斥量*当你的EXE由于外部因素(“杀死进程”,蓝屏死机,或者更可能的电源故障)而死亡时,没有任何东西可以帮助你。只有一个交易是为了让你的插入安全而设计的,为什么你不喜欢它们? – 2009-06-28 11:55:10

回答

6

假设“呼叫中止方法”意味着使用Thread.Abort中止线程。 Don't do that

你正在崩溃你的应用程序。监视器有很多更干净的方法。

尽管如此,当您的应用程序崩溃时,您不应该在数据库中获取不一致的数据,这就是为什么您拥有ACID属性的数据库事务。

非常重要的编辑 你说:你不使用交易的性能原因,而是使用互斥体。这是错误在相当多的水平。首先,事务可以使某些操作更快,例如,尝试在表中插入10行,在事务中再次尝试,事务版本将更快。其次,如果您的应用崩溃,会发生什么情况?您是否损坏了数据库?当您的应用的多个实例正在运行时会发生什么?或者当您在查询分析器中针对您的数据库运行报告?

8

只要两个线程都没有被标记为背景线程,应用程序将继续运行,直到两个线程退出。所以你需要做的就是分别让每个线程完全退出。在写入数据库的线程的情况下,这可能意味着耗尽生产者/消费者队列并检查退出标志。

我展示了一个合适的生产者/消费者队列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"); 
    } 
} 
3

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