【问题标题】:Thread Monitoring C#线程监控 C#
【发布时间】:2010-09-26 11:37:00
【问题描述】:

在我的应用程序中,我有 6 个数组,它们代表我的应用程序执行的 6 个作业。每个作业基本上都与数据库交互并填充数组的每个元素。
我所做的是创建 6 个线程并使 6 个数组全局化,以便线程可以填充它们。我还创建了一个包含 6 个 bool 元素的数组(ThreadsAlive)。当一个线程完成它的执行时,它在 bool 数组中设置一个标志.我创建了一个作业监视线程(threadwatcher)来监视这个布尔线程。当该数组中的所有元素都设置为false时,我将确保我的作业已完成。

现在,问题是,由于 Oledb 驱动程序中的一些错误,ExecuteReader() 语句卡在某个线程中并且永远不会恢复,我的应用程序将永远继续。实际上,可以“解决”错误可以重新启动该特定作业。下次该作业可能会成功运行。
我的计划是我将所有 6 个线程作为字段,并与 ThreadsAlive 数组一起,我还将维护一个 DateTime 的 LastActivityOfThreads 数组。
所有作业线程在执行查询时都会更新该数组中的时间。现在我的作业观察线程将监视任何线程的最后活动时间是否超过 3 分钟前。如果发生这种情况,它将杀死该线程并重新启动它。

只是想知道如何在不引发异常的情况下杀死任何线程。

更新:我这样做了,它显示“线程被中止”的异常

更新:也许我为每个操作使用单独的进程(exe),并在主应用程序中不断监视进程。如果一个进程比平时花费更长的时间,我会杀死该进程并重新启动它。
但在这种情况下,运行的 6 个进程将如何给我 6 个数组的数据?

更新:是否有可能在池中,如果我发现任何线程挂起,我会使用
th = new Thread(Fun_Name) 并让旧线程在原处。

【问题讨论】:

  • 您应该维护一个基于计数器的同步对象,例如信号量,而不是维护一个由六个布尔值组成的数组并不断地轮询它们。这样,您可以在六个线程上进行更有效的等待。也许更简单,你可以循环六个 Join()s。
  • 实际上问题不在于同步,而是我想以某种方式克服的 ExecuteReader 中的错误。
  • 我认为你不应该做这种复杂的事情来避免 ExecuteReader 中的错误,我实际上认为你更有可能滥用它。我建议您发布另一个与 ExecuteReader 相关的问题,看看它是否真的是一个错误,而不仅仅是“用户错误”。

标签: c# multithreading


【解决方案1】:

哎呀……恐怕那个有问题的 OLEDB 驱动程序将非常难以解决。您杀死线程的策略(可能是通过Thread.Abort)可能很危险,因为它可能会破坏应用程序域并可能破坏进程。您有时可以通过将行为不端的代码放在新的AppDomain 中然后中止卡在该应用程序域中的线程来隔离这些问题,但是没有保证它会工作并且不会使进程处于损坏状态。您唯一安全的选择是将调用 OLEDB 驱动程序的代码放入单独的进程中。但是,这意味着您必须创建所有管道来进行进程间通信。它肯定需要更多的工作,但它仍然是易于管理的。

【讨论】:

    【解决方案2】:

    您不能在不引发异常的情况下立即终止线程。它的设计旨在确保一致的资源锁定。如果某个布尔标志(例如_should_stop)为真,您可以为每个线程编写一个方法来停止它。

    【讨论】:

    • 问题是它永远卡在ExecuteReader()中时无法读取flag。
    • 它只是停在那里,没有任何例外。
    【解决方案3】:

    您可以使用自动重置事件或手动重置事件等事件等待句柄类来通知其他线程。在这种情况下,您不需要维护 bool 变量。您还可以指定线程操作的超时时间。如果事件没有在指​​定的超时时间内设置,您可以假设存在一些异常。

    看看一本很好的书http://www.albahari.com/threading/中解释的线程同步概念

    【讨论】:

      【解决方案4】:

      我想您可能会发现CountDownLatch 非常有用:

      public class CountDownLatch
      {
          private int m_remain;
          private EventWaitHandle m_event;
      
          public CountDownLatch(int count)
          {
              if (count < 0)
                  throw new ArgumentOutOfRangeException();
              m_remain = count;
              m_event = new ManualResetEvent(false);
              if (m_remain == 0)
              {
                  m_event.Set();
              }
          }
      
          public void Signal()
          {
              // The last thread to signal also sets the event.
              if (Interlocked.Decrement(ref m_remain) == 0)
                  m_event.Set();
          }
      
          public void Wait()
          {
              m_event.WaitOne();
          }
      }
      

      这里有一个粗略的例子来说明你将如何使用它:

      ManualResetEvent hasWork = new ManualResetEvent(false);
      CountDownLatch countDown = new CountDownLatch(6);
      List<Thread> threads = new List<Thread>();
      volatile bool running = true;
      int timeoutPeriod = 60 * 1000 * 3; // 3 minutes
      
      for(int i = 0; i < 6; i++)
      {
          Thread t = new Thread(()=>
          {
              try
              {
                  // Block till there is some work
                  hasWork.WaitOne();
      
                  while(running)
                  {
                      // Perform the work
                      PerformWork();
                  }
              }
              catch(InterruptException)
              {
                  // Ignore if you're Interrupting the thread yourself
              }
              finally
              {
                  // Signal you're done
                  countDown.Signal();
              }
          });
      
          t.IsBackground = true;
          t.Start();
          threads.Add(t);
      }
      
      Thread workerKiller = new Thread(()=>
      {
          // If you need to kill your threads if they
          // are working for too long, then you can 
          // setup a "worker killer" to kill them if
          // some condition is met... 
      
          // In this case you give the threads a maximum 
          // of 3 minutes to complete the work and then 
          // you stop all of them.
          Thread.Sleep(timeoutPeriod);
      
          // Interrupt the threads
          running = false;
          foreach(Thread t in threads)
          {
              t.Interrupt();
          }
      });
      
      workerKiller.IsBackground = true;
      workerKiller.Start();
      
      // Lift the barrier
      hasWork.Set();
      
      // Wait for all the threads to signal 
      // that they have completed their work.
      countDown.Wait();
      

      最后:

      现在,问题是,由于一些 Oledb 驱动程序中的错误, ExecuteReader() 语句卡在 一些线程,永远不会恢复和我的 应用程序永远持续下去。

      我认为您需要弄清楚 Oledb 驱动程序中的这个“错误”是什么,并找到一种方法来避免它,或者在更有可能发生的情况下,确保您没有做错任何事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-15
        • 1970-01-01
        相关资源
        最近更新 更多