持续监视线程的CPU使用情况

时间:2017-02-16 10:20:11

标签: c# multithreading timer windows-services

我需要Windows服务中的一个线程,它会持续监控CPU使用率(可能每5秒钟)。如果CPU使用率低,则应激活其他线程。

我找到了来自此SO Question的示例CPU使用情况监控代码(我的帖子也在下面给出)。这是控制台应用程序的代码,为了使Timer保持活跃,此人最后使用Console.ReadLine();

CPU使用率控制台应用程序:

using System;
using System.Diagnostics;
using System.Timers;
using System.Threading;
using System.Collections.Generic;

namespace CPUPerformanceMonitor
{
    class MonitoringApplication
    {
        protected static PerformanceCounter cpuCounter;
        protected static PerformanceCounter ramCounter;

        public static void TimerElapsed(object source, ElapsedEventArgs e)
        {
            float cpu = cpuCounter.NextValue();
            float ram = ramCounter.NextValue();
            Console.WriteLine(string.Format("CPU Value: {0}, ram value: {1}", cpu, ram));
        }

        public static void Main()
        {
            cpuCounter = new PerformanceCounter();
            cpuCounter.CategoryName = "Processor";
            cpuCounter.CounterName = "% Processor Time";
            cpuCounter.InstanceName = "_Total";

            ramCounter = new PerformanceCounter("Memory", "Available MBytes");

            try
            {
                System.Timers.Timer t = new System.Timers.Timer(1200);
                t.Elapsed += new ElapsedEventHandler(TimerElapsed);
                t.Start();
                Thread.Sleep(10000);
            }
            catch (Exception e)
            {
                Console.WriteLine("catched exception");
            }

            while (true) //Another sample BAD way to keep the timer alive
            { }

            //Console.ReadLine(); //just to keep the time alive
        }
    }
}

问题:如何在Windows服务应用程序中实现它。我的意思是,我如何让线程保持活力。

我的Windows服务结构:

我调用了一个Thread回调方法OnStart()。此线程Callback方法调用类StartCPUMonitorinig()的{​​{1}}方法(包含CPUMonitor的代码)。

Timer

1 个答案:

答案 0 :(得分:0)

要将其实现为Service类型,您必须考虑在何处以及如何输出效果数据。使用Windows服务我可以建议制作另一个应用程序或覆盖,然后在服务结束更新时显示这些值。这可以使用共享内存,文件,数据库,Windows消息泵,标准输出等来完成。

考虑到这些事情,您实际上可以通过制作服务对象来开始制作服务:

public class MeService : ServiceBase
{
    // for the ability to redirect stream
    [DllImport("Kernel32.dll", SetLastError = true) ]
    public static extern int SetStdHandle(int device, IntPtr handle); 

    // entry point
    public static void Main(string[] args)
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new MeService()
        };
        ServiceBase.Run(ServicesToRun);
    }

    PerformanceObject pObject; // object to retrieve and return performance status
    IContainer components;
    FileStream fStream;
    public MeService()
        : base()
    {
        components = new Container(); // initialize components holder
        ServiceName = "MeService"; // set your service name
    }

    // Here check for custom commands on your service
    protected override void OnCustomCommand(int command)
    {
        if(command == 1)
        {
            // redirect stream
            fStream = new FileStream("<path_to_your_out_file>", <FileMode.Here>, <FileAccess.Here>);
            IntPtr streamHandle = fStream.Handle;
            SetStdHandle(-11, handle); // DWORD -11  == STD OUT
        }
        else if(command == 1337 && pObject != null) // example command
        {
            // write string.Format("CPU Value: {0}, ram value: {1}", cpu, ram);
            // into your service's std out
            Console.WriteLine(pObject.GetPerformance()); 
        }
        base.OnCustomCommand(command);
    }

    // whenever service starts create a fresh performance counter object
    protected override void OnStart(string[] args) // will be called when service starts
    {
        pObject = new PerformanceObject();
    }

    // called whenever service is stopped
    protected override void OnStop()
    {
        // remove performance counter object 
        pObject.Dispose();
        pObject = null;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (components != null)
            {
                components.Dispose();
            }

            if (pObject != null)
            {
                pObject.Dispose();
            }
        }
        base.Dispose(disposing);
    }
}

现在完成后,您可以创建“显示”应用程序。这应该将服务的标准重定向到它自己的阅读器,以使您能够从该流中读取。

class Program
{
    static void Main(string[] args)
    {
        FileStream fileStream = new FileStream("<PATH_TO_THE_SAME_FILE_AS_SERVICE>", <FileMode.Here>, <FileAccess.Here>);
        // create service controller that will control "MeService" service
        ServiceController Controller = new ServiceController("MeService");
        if (Controller.Status == ServiceControllerStatus.Stopped)
        {
            Controller.Start();
        }

        while (Controller.Status != ServiceControllerStatus.Running)
        ;

        Controller.ExecuteCommand(1); // redirect the stream.           

        string command = string.Empty;
        while( ( command = Console.ReadLine() ) != "exit" )
        {
            if(command == "refresh")
            {
                if (Controller.Status == ServiceControllerStatus.Running)
                {
                    Controller.ExecuteCommand(1337);
                    string performance = fileStream.ReadLine();
                    Console.WriteLine(performance);
                } 
            }
        }
    }
}

现在,你所要做的就是在你的服务中创建一个安装文件并创建你已经拥有的PerformanceObject,但是你需要修改它以便与上面的代码片段一起使用。