简体   繁体   English

如何让线程“回报”到主线程?

[英]How can i make a thread “report back” to main thread?

Im making a app that monitors stuff on my computer, and i want to make it somewhat more difficult then just implementing a while loop. 我正在制作一个应用程序,监视我的计算机上的东西,我想让它更难以实现一个while循环。

So my question is how do i do it if i would like to fetch cpu load in a seperate thread, that updates a static variable in class 所以我的问题是如果我想在一个单独的线程中获取cpu加载,如何在类中更新静态变量,我该怎么做呢

namespace threads
{
    class Program
    {
        static int cpuload = 0;

        static void Main(string[] args)
        {
            while (true)
            {
                Thread th = new Thread(new ThreadStart(CheckCPULoad));
                th.Start();

                Thread.Sleep(1000); // sleep the main thread

                th.Abort();

                Console.WriteLine("load: {0}%", cpuload);
            }
        }

        static void CheckCPULoad()
        {
            // things are updated every 3 secs, dummy data
            Thread.Sleep(3000);

            Random rnd = new Random();
            cpuload++;// = rnd.Next(0, 100); // dummy data
        }
    }
}

As it is "load: 0%" is printed every time. 因为每次都打印“load:0%”。 what do i need to fix to make it show 我需要修复什么才能让它显示出来

load: 0% 
load: 0% 
load: 0% 

?

thanks 谢谢

In order to "report back" to the main thread, the main thread has to be "listening". 为了“回报”主线程,主线程必须是“监听”。 Which means, still running in a while loop and checking some kind of a queue for new items that represent the reports. 这意味着,仍然在while循环中运行并检查某种类型的队列以查找代表报告的新项目。

What you basically need is a queue where the worker thread will put its reports, and the main thread will periodically check this queue for reports from the worker. 您基本上需要的是一个队列,其中工作线程将放置其报告,主线程将定期检查此队列以获取来自该工作者的报告。

You have two main approaches: 您有两种主要方法:

  1. A blocking queue. 阻塞队列。 Means that when there are no items the caller thread blocks until items arrive. 意味着当没有项目时,调用者线程将阻塞直到项目到达。 This is good if the main thread has nothing to do except wait for items in the queue. 如果主线程除了等待队列中的项目之外没有任何操作,这是很好的。
  2. A non-blocking queue. 非阻塞队列。 Means that it returns immediately to the caller regardless of the items count. 意味着无论项目数是多少,它都会立即返回给调用者。 This is good if you want your main thread to be busy doing stuff and sometimes checking the queue for reports. 如果您希望主线程忙于执行操作并且有时检查队列中的报告,那么这很好。

If your application is a UI application you automatically get the first approach, as this is how the UI works. 如果您的应用程序是UI应用程序,则会自动获得第一种方法,因为这是UI的工作方式。 To add "an item" you can use Control.BeginInvoke (in winforms) or Dispatcher.BeginInvoke (in wpf). 要添加“项目”,您可以使用Control.BeginInvoke(在winforms中)或Dispatcher.BeginInvoke(在wpf中)。

The code you're using there starts the CheckCPULoad thread, waits 1 second and then aborts it. 你在那里使用的代码启动CheckCPULoad线程,等待1秒然后中止它。 However, the first thing the CheckCPULoad thread does is to sleep for 3 seconds. 但是,CheckCPULoad线程做的第一件事就是睡3秒钟。 So you never actually reach the cpuload++ instruction. 所以你永远不会真正达到cpuload++指令。 I suspect this would be closer to what you intended: 我怀疑这将更接近你的意图:

namespace threads
{
    class Program
    {
        static int cpuload = 0;

        static void Main(string[] args)
        {
            Thread th = new Thread(new ThreadStart(CheckCPULoad));
            th.Start();

            while (true)
            {
                Thread.Sleep(1000);
                Console.WriteLine("load: {0}%", cpuload);
            }

            th.Abort(); // Don't ever reach this line with while (true)
        }

        static void CheckCPULoad()
        {
            while (true)
            {
                Thread.Sleep(3000);
                cpuload++;
            }
        }
    }
}

Use a timer and events instead. 请改用计时器和事件。 This way you avoid your sleeping/busy waiting. 这样可以避免您的睡眠/忙碌等待。 Also consider using Interlocked.Increment as suggested if several threads can modify the static variable at the same time. 如果多个线程可以同时修改静态变量,也可以考虑使用Interlocked.Increment。

using System;
using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;

namespace CpuLoad
{
    internal class Program
    {
        private static int cpuload;
        private static readonly AutoResetEvent autoEvent = new AutoResetEvent(false);

        private static void Main(string[] args)
        {
            var timer = new Timer(3000);
            timer.Elapsed += CheckCPULoad;
            timer.Start();

            while (true)
            {
                autoEvent.WaitOne();
                autoEvent.Reset();
                Console.WriteLine(cpuload);
            }
        }

        private static void CheckCPULoad(object sender, ElapsedEventArgs e)
        {
            cpuload++;
            autoEvent.Set();
        }
    }
}

If i get you right, this should solve your purpose. 如果我找对你,这应该可以解决你的目的。 Notice the while loop inside the CheckCPULoad() method. 注意CheckCPULoad()方法中的while循环。

class Program 
        {
            static int cpuload = 0;

    static void Main(string[] args)
    {
        Thread th = new Thread(new ThreadStart(CheckCPULoad));
        th.Start();

        while (true)
        {
            Thread.Sleep(1000);
            Console.WriteLine("load: {0}%", cpuload);
        }
        th.Abort(); // Don't ever reach this line with while (true)        
    }

    static void CheckCPULoad()
    {
        while (true)
        {
            Thread.Sleep(3000);
            cpuload++;
        }
    }


}

Instead of cpuload++ try using 而不是cpuload++尝试使用

Interlocked.Increment(ref cpuload);

Check - http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx 检查 - http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx

The thread sleeps for 3 secs. 线程休眠3秒。 You abort it after 1. Go figure :) 你在1之后中止它。去图:)

With callback you can do that 通过回调,您可以做到这一点

here is an exsample: 这是一个例子:

public class Example2
{
    // Declaration - Take 1 parameter, return nothing
    public delegate void LogHandler(string message);

    // Instantiation - Create a function which takes delegate as one parameter
    // Verify if it is null before you use it
    public void Process(LogHandler logHandler)
    {
        if (logHandler != null)
        {
            logHandler("Process() begin");
        }

        if (logHandler != null)
        {
            logHandler("Process() end");
        }
    }
}

public class Example2DelegateConsumer
{
    // Create a method with the same signature as the delegate
    static void Logger(string s)
    {
        Console.WriteLine(s);
    }

    public static void Main(string[] args)
    {
        Example2 ex2 = new Example2();

        // Invocation in the client
        Example2.LogHandler myLogger = new Example2.LogHandler(Logger);
        ex2.Process(myLogger);
    }
}

In addition to my original (plagiarised) answer below, this sort of situation where you're observing a set of values over time is a great fit for Reactive Extensions for .NET (http://blogs.msdn.com/b/rxteam/). 除了我在下面的原始(剽窃)答案之外,这种情况下你随着时间的推移观察一组值非常适合.NET的Reactive Extensions(http://blogs.msdn.com/b/rxteam /)。 You can get the desired effect with Rx thus: 您可以使用Rx获得所需的效果:

static void Main()
{
    var cpuLoadSequence = Observable.GenerateWithTime(
        0, // initial value
        i => true, // continue forever
        i => i + 1, // increment value
        i => i, // result = value
        i => TimeSpan.FromSeconds(3)); // delay 3 seconds

    using (cpuLoadSequence.Subscribe(x => Console.WriteLine("load: {0}%", x)))
    {
        Console.WriteLine("Press ENTER to stop.");
        Console.ReadLine();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM