【问题标题】:Windows Service to run constantlyWindows 服务不断运行
【发布时间】:2011-06-19 09:04:00
【问题描述】:

我创建了一个名为 ProxyMonitor 的 Windows 服务,我目前正处于按我想要的方式安装和卸载该服务的阶段。

所以我像这样执行应用程序:

C:\\Windows\\Vendor\\ProxyMonitor.exe /install

非常不言自明,然后我到 services.msc 并启动服务,但是当我这样做时,我收到以下消息:

本地计算机上的代理监视器服务启动然后停止。如果没有工作要做,一些服务会自动停止,例如,性能日志和警报服务

我的代码如下所示:

public static Main(string[] Args)
{
    if (System.Environment.UserInteractive)
    {
        /*
            * Here I have my install logic
        */
    }
    else
    {
        ServiceBase.Run(new ProxyMonitor());
    }
}

然后在 ProxyMonitor 类中我有:

public ProxyMonitor()
{
}

protected override void OnStart(string[] args)
{
    base.OnStart(args);
    ProxyEventLog.WriteEntry("ProxyMonitor Started");

    running = true;
    while (running)
    {
        //Execution Loop
    }
}

onStop() 我只是将running 变量更改为false

我需要做些什么才能使服务始终处于活动状态,因为我需要监控我需要跟踪更改等的网络。


更新:1

protected override void OnStart(string[] args)
{
     base.OnStart(args);
     ProxyEventLog.WriteEntry("ProxyMonitor Started");

     Thread = new Thread(ThreadWorker);
     Thread.Start();
 }

ThreadWorker 内我有ProxyEventLogger.WriteEntry("Main thread entered"),它不会被解雇。

【问题讨论】:

    标签: c# windows-services


    【解决方案1】:

    为什么不在 Windows 服务类型的解决方案中创建一个新项目?这会设置您需要实现的所有结构,甚至包括服务启动/停止事件的处理程序。

    【讨论】:

    • 这部分是一种培训体验,我更愿意从底层学习它的完成方式。
    • 我认为即使是培训(尤其是培训?),您最好了解 VS 如何为 Windows 服务创建脚手架,然后您可以了解它为什么工作以及它是如何工作的。而不是自下而上,正如您所发现的那样,更令人沮丧。
    • 这是真的,这一点值得商榷,但这里并非如此。此应用程序已完成 60%,也许在我的下一个应用程序中,我将从 Windows 服务模板开始。
    【解决方案2】:

    您需要退出您的OnStart 处理程序,以便服务控制器意识到您的服务已实际启动。为了让它像你想要的那样工作,你可以启动一个计时器,它以一定的时间间隔计时并在计时时进行处理。

    编辑:

    尝试在OnStart 中放置 System.Diagnostics.Debugger.Launch() 以查看发生了什么(并在 ThreadWorker 中放置断点)。我建议将其包装在 #if DEBUG 中以确保它不会被部署。

    我刚刚也意识到你没有给你的Thread 一个名字:

     Thread myThread = new Thread(ThreadWorker);
     myThread.Start();
    

    【讨论】:

    • 应该有返回码,比如return 0return false,和一个线程也行吧?
    • 否; OnStart 事件处理程序返回 void。只要它在合理的时间范围内(我认为大约一分钟)退出,服务控制器就会很高兴。
    【解决方案3】:

    当然不会在OnStart 方法中添加while 循环。这将告诉操作系统该服务尚未启动,因为它无法从OnStart 方法安全退出。我通常创建一个在OnStart 方法中启用的Timer。然后在Ticks 方法中,我确实调用了必要的方法以使应用程序运行。

    或者,您可以执行以下操作:

    // The main entry point for the process 
    static void Main() 
    { 
        System.ServiceProcess.ServiceBase[] ServicesToRun; 
        ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() }; 
        System.ServiceProcess.ServiceBase.Run(ServicesToRun); 
    } 
    

    有关 Windows 服务的更多信息,您可以获取骨架示例here

    【讨论】:

      【解决方案4】:

      OnStart() 回调需要及时返回,因此您需要启动一个线程来执行您的所有工作。我建议将以下字段添加到您的课程中:

      using System.Threading;
      private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
      private Thread _thread;
      

      _thread 字段将保存对您在 OnStart() 回调中创建的 System.Threading.Thread 对象的引用。 _shutdownEvent 字段包含一个系统级事件构造,用于通知线程在服务关闭时停止运行。

      OnStart() 回调中,创建并启动您的线程。

      protected override void OnStart(string[] args)
      {
           _thread = new Thread(WorkerThreadFunc);
           _thread.Name = "My Worker Thread";
           _thread.IsBackground = true;
           _thread.Start();
      }
      

      您需要一个名为WorkerThreadFunc 的函数才能使其工作。它必须与System.Threading.ThreadStart 委托签名匹配。

      private void WorkerThreadFunc()
      {
      }
      

      如果你没有在这个函数里放任何东西,线程会启动然后立即关闭,所以你必须在里面放一些逻辑,在你工作的时候基本上保持线程处于活动状态。这就是_shutdownEvent 派上用场的地方。

      private void WorkerThreadFunc()
      {
          while (!_shutdownEvent.WaitOne(0)) {
              // Replace the Sleep() call with the work you need to do
              Thread.Sleep(1000);
          }
      }
      

      while 循环检查ManualResetEvent 以查看它是否已“设置”。由于我们在上面使用false 初始化了对象,因此此检查返回 false。在循环中,我们休眠 1 秒。您需要将其替换为您需要做的工作 - 监控代理设置等。

      最后,在您的 Windows 服务的 OnStop() 回调中,您希望向线程发出停止运行的信号。这很容易使用_shutdownEvent

      protected override void OnStop()
      {
           _shutdownEvent.Set();
           if (!_thread.Join(3000)) { // give the thread 3 seconds to stop
               _thread.Abort();
           }
      } 
      

      希望这会有所帮助。

      【讨论】:

      • 谢谢你,我明白了,现在它按预期运行了:)
      • 很高兴为您提供帮助。值得一提的是,我有几个详细的 SO 教程,它们展示了 (1) 如何在事件查看器 (stackoverflow.com/questions/593454/…) 中拥有自己的日志,以及 (2) 如何在不需要 InstallUtil 的情况下安装/卸载您的服务。 exe (stackoverflow.com/questions/1195478/…)。
      • 是的,非常感谢您的帮助,我之前在寻找胜利的过程中阅读了您的第一篇文章,如果您想查看我的代码,我将其发布在这里并留下评论我处于什么阶段。 pastebin.com/t8QQzXC9
      • @My-Name-Is,示例的组织方式,一旦调用_shutdownEvent.Set(),线程将停止执行。那是因为WorkerThreadFunc() 中的while 循环将退出。如果您想暂停并稍后恢复同一个线程,请创建另一个 ManualResetEvent 对象来控制线程的该方面。
      • @shaikhspear 是的,无论如何它应该是这样的。我更正了。
      【解决方案5】:

      使用控制台应用程序演示的示例代码。希望这会有所帮助..

       class Program
      {
          private static CancellationTokenSource _cancellationTokenSource;
          private static ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
          private static Thread _serviceStartThread;
          private static Thread _serviceStopThread;
      
          private static int workcounter = 0;
          static void Main(string[] args)
          {
      
              _cancellationTokenSource = new CancellationTokenSource();
              _serviceStartThread = new Thread(DoWork);
              _serviceStopThread = new Thread(ScheduledStop);
              StartService();
              StopService();
          }
      
          private static void StartService()
          {
              _serviceStartThread.Start();
      
          }
      
          private static void StopService()
          {
              _serviceStopThread.Start();
          }
      
      
          /// <summary>
          /// Triggers a cancellation event for stopping the service in a timely fashion.
          /// </summary>
          private static void ScheduledStop()
          {
              while (!_shutdownEvent.WaitOne(0))
              {
                  if (workcounter == 10)
                  {
                      _cancellationTokenSource.Cancel();
                  }
              }
          }
      
          /// <summary>
          /// Represents a long running Task with cancellation option
          /// </summary>
          private static void DoWork()
          {
      
              while (!_shutdownEvent.WaitOne(0))
              {
                  if(!_cancellationTokenSource.Token.IsCancellationRequested)
                  {
                      workcounter += 1;
                      Console.Write(Environment.NewLine);
                      Console.Write("Running...counter: " + workcounter.ToString());
                      Thread.Sleep(1000);//Not needed, just for demo..
                  }
                  else
                  {
                      Console.Write(Environment.NewLine);
                      Console.Write("Recieved cancellation token,shutting down in 5 seconds.. counter: " + workcounter.ToString());
                      _shutdownEvent.Set();
                      Thread.Sleep(5000);//Not needed, just for demo..
                  }
      
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        在我看来,解决这个问题最简单的方法是:

        protected override void OnStart(string[] args)
        {            
            new Task(() =>
            {
                    new ProxyMonitor();                    
            }).Start();    
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-16
          • 2013-06-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多