【问题标题】:Threadpool is getting used by windows service problemWindows 服务问题正在使用线程池
【发布时间】:2009-11-18 15:50:16
【问题描述】:

我创建了一个 Windows 服务,它目前有三个计时器。第一个定时器每 15 秒唤醒一次,第二个定时器每分钟唤醒一次。第三个计时器每天都在醒来。

问题是这些每次都产生新线程,并且有一次线程池完全用完。是否只产生 3 个线程而不产生更多新线程。

我的代码如下所示:

protected Onstart()
{
  var timer1  = new TImer();
  timer.Elapsed += Event1;
  timer1.interval = 60000;
  timer1.start();

  var timer2  = new TImer();
  timer2.Elapsed += Event2;
  timer2.interval = 60000;
  timer2.start();
}

private Event1(object,elapsedeventargs)
{
  var workerthread1 = **new thread**(workerthreadfunc1)
  workerthread1.start();
}

private Event2(object,elapsedeventargs)
{
  var workerthread2 = **new thread**(workerthreadfunc2)
  workerthread2.start();
}

所以你可以看到它正在创建新线程,这将在某个时候用完线程池中的所有线程并突然停止 Windows 服务。目前它正在停止并记录事件 ID 为 5000 的事件日志。

【问题讨论】:

  • 如果您告诉我们或向我们展示workerthreadfuncN的作用可能会更清楚。看起来你每 15 秒、每分钟和每一天都有一些你想要完成的工作。至于日常工作,这可能由某种任务调度程序/cron 作业更好地处理。我的回答将基于这是您的目标这一假设。
  • 所以我用过这个。 ThreadPool.QueueUserWorkItem(new WaitCallback(WorkerThreadFunction1));而且我认为有人建议 processtimerevent 已经在一个线程上。所以我牢记这一点,如果这个使用线程池的解决方案失败,我会实施。 ——

标签: c# windows multithreading threadpool


【解决方案1】:

您的问题不在于线程池。每次您的计时器之一“滴答”时,您都在创建自己的线程。我不知道 workerthreadfunc1 和 workerthreadfunc2 在做什么,但是如果它们不返回,那么您将继续创建越来越多的线程。

如果您使用 System.Timers.Timer,则 Elapsed 事件已经在 ThreadPool 线程上。为什么不在那里执行您想要的操作?

【讨论】:

  • 谢谢建议,我希望在使用线程池后服务不会再次停止:)
  • @alice:正如我所说,您在线程池的线程中收到 elapsed 事件,因此您不需要为池排队另一个工作项。但我会首先检查线程函数是否有问题。好像他们再也不会回来了。
  • 我目前在每个工作线程函数中使用 try 和 catch。但看起来它根本没有捕捉到异常。
【解决方案2】:

不要产生新线程,而是使用ThreadPool

【讨论】:

    【解决方案3】:

    我会将设计更改为不包含任何计时器。在开始时,创建 3 个线程,并在 workerthreadfunc1 和 workthreadfunc2 中完成的工作循环,并在线程的开始或结束时使用 thread.sleep 持续适当的时间(15 秒、1 分钟等......)环形。您可能希望在循环的开头添加一些检查,以查看是否有人试图停止服务,或者是否已经启动了另一个服务。

    【讨论】:

      【解决方案4】:

      您可以尝试只创建尚未创建的线程。在类级别声明 workerthread1 并执行以下操作:

      if(workerthread1 != null)
      {
            workerthread1 = new thread(workerthreadfunc1);
      }
      

      【讨论】:

      • 那段代码行不通,workerthread1 还没有被实例化,但是他可以让它成为他正在从事这项工作的任何类/模块的变量。
      • 对不起。在提交之前应该再读一遍:)
      【解决方案5】:

      @marr75 @扎克

      这两个都是很好的建议,但为什么不呢:

      int x = 0; //last exec timestamp(ts)
      int s = 0; //15 s ts
      int m = 0; //min ts
      int d = 0; //day ts
      while(check for event()){ //e.g. stop service etc.
         if((x - s)>15){
            //code for ever 15 s here
            s = currentTime();
         }
         if ((x - m)>60){
            //code for every min here
            m = currentTime();
         }
         if ((x - d)> 86400)(
            //code for every day here
            d = currentTime();
         }
         sleep(5000); // or wait() w/e sleeps the thread for 15s
         x = currentTime();
      }
      

      然而,这假设您做的是相对轻松的任务 如果您执行较重的任务,例如 SQL 查询和插入或其他内容,请确保线程在完成后自行终止。

      您可能会发生溢出,因为您的 15s 和 min 工作线程分别需要超过 15s 和 1 min 的时间来执行,如果这是真的,您将更快地添加线程,然后它们最终终止导致溢出,因为 msergeant 试图也就是说,只有在你的旧工作线程完成时才添加一个新线程。

      【讨论】:

        猜你喜欢
        • 2019-09-05
        • 1970-01-01
        • 2011-04-08
        • 1970-01-01
        • 2011-07-14
        • 2020-10-02
        • 1970-01-01
        • 2011-12-07
        • 1970-01-01
        相关资源
        最近更新 更多