【问题标题】:Continously monitoring thread for CPU usage持续监控线程的 CPU 使用率
【发布时间】:2017-02-16 10:20:11
【问题描述】:

我需要 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-Service 应用程序中实现它。我的意思是,我如何让线程保持活力。

我的 Windows 服务结构:

我调用了一个线程回调方法OnStart()。此线程回调方法调用类CPUMonitorStartCPUMonitorinig() 方法(其中包含Timer 的代码)。

    public void CPUMonitorinigThreadCallback()
    {
        //If nothing is there in this function, the thread will start up and then immediately shutdown. To deal with this situation, use "_shutdownEvent"
        //The while loop checks the ManualResetEvent to see if it is "set" or not.
        while (!_shutdownEvent.WaitOne(0))
        {
            // Replace the Sleep() call with the work you need to do
            //Sleep(1000);
            objCPUMonitor.StartCPUMonitorinig();
        }

    }

【问题讨论】:

  • 我认为您以错误的方式处理此问题。听起来您基本上是在尝试完成一些工作,但前提是 CPU 利用率较低。您是否考虑过可以简单地降低工作线程的优先级(后台、空闲等)?如果我误解了你的意图,你能否给我更广泛的了解你想要达到的目标(总体而言)?
  • 为什么需要线程。您可以使用计时器每 5 秒触发一次。
  • Windows 服务线程不进入睡眠状态。你基本上不需要做任何事情它会保持活力,只要你注册事件,它们就会被提升\
  • @ManfredRadlwimmer:你是对的。我有一个线程可以持续监控是否插入了 USB 记忆棒。当且仅当 CPU 使用率低时,我才需要从 USB 复制文件。大图:USB一插入就开始监控CPU使用率,当CPU使用率低时复制文件。
  • 那么 Manfred 是对的——只是降低工作线程的优先级。

标签: c# multithreading timer windows-services


【解决方案1】:

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

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

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,但您必须对其进行一些修改才能与上述 sn-ps 一起使用。

【讨论】:

    猜你喜欢
    • 2016-11-27
    • 2016-04-29
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 2012-11-15
    相关资源
    最近更新 更多