C# 从一个线程读取变量并从另一个线程写入变量的正确方法?

C# 从一个线程读取变量并从另一个线程写入变量的正确方法?,c#,multithreading,C#,Multithreading,我正在尝试创建一个具有2个线程的应用程序。在主线程中,我有一个变量(Int32),我只从主线程读取它 现在我有另一个线程在循环中运行,只要程序在运行,这个线程就会创建一个“心跳”,当到达某个点时,我想更新上面提到的变量。该变量仅从该heartbeat线程写入,从不从任何其他线程写入 为了保持精度(QueryPerformanceCounter级别),我希望避免心跳线程上任何可能的阻塞 以下是一个简化版本: using System; using System.Threading; namesp

我正在尝试创建一个具有2个线程的应用程序。在主线程中,我有一个变量(Int32),我只从主线程读取它

现在我有另一个线程在循环中运行,只要程序在运行,这个线程就会创建一个“心跳”,当到达某个点时,我想更新上面提到的变量。该变量仅从该heartbeat线程写入,从不从任何其他线程写入

为了保持精度(QueryPerformanceCounter级别),我希望避免心跳线程上任何可能的阻塞

以下是一个简化版本:

using System;
using System.Threading;

namespace ConsoleApp2
{
    class Program
    {
        static int Interval = 0;

        static void Heartbeat()
        {
            int counter = 0;
            while (counter < 100) {
                counter++;
                Console.WriteLine($"Heartbeat : {counter}");
                if (counter % 10 == 0) {
                    Interval = counter;
                }
                Thread.Sleep(100);
            }
        }

        static void Main(string[] args)
        {
            Thread heartbeat = new Thread(Heartbeat);
            heartbeat.Start();

            while (Interval < 100) {
                Console.WriteLine($"Interval  : {Interval}");
                Thread.Sleep(100);
            }

            Console.ReadLine();
        }
    }
}
  • 只要主线程中读取的值是合法值(在
    Heartbeat
    线程中计算),而不是其他值,我就可以接受它。例如,如果在我为这个循环读取该值的同时更新该值,则可以获取旧值或新值,只要它不是某个不相关的值。(如果它读取旧值,它将在下一个循环中读取新值,对吗?)

  • 即使没有阻塞和非常短的工作时间,您的计时器线程也会发生打滑,因为它的工作时间不是0。我想你最好有个计时器

    请参阅已在内置多线程设置中运行

    基于服务器的System.Timers.Timer类设计用于多线程环境中的工作线程。服务器计时器可以在线程之间移动以处理引发的已用事件,从而在按时引发事件方面比Windows计时器更准确

    如果SynchronizingObject属性为null,则在线程池线程上引发已用事件。如果已用事件的处理持续时间超过间隔,则可能会在另一个线程池线程上再次引发该事件。在这种情况下,事件处理程序应该是可重入的

    最后:

    小费

    请注意,.NET包含四个名为Timer的类,每个类提供不同的功能:

    • System.Timers.Timer(本主题):定期触发事件。该类旨在用作多线程环境中基于服务器的组件或服务组件;它没有用户界面,在运行时不可见
    • System.Threading.Timer:定期对线程池线程执行单个回调方法。回调方法是在实例化计时器时定义的,不能更改。与System.Timers.Timer类类似,该类旨在用作多线程环境中基于服务器的组件或服务组件;它没有用户界面,在运行时不可见
    • System.Windows.Forms.Timer(仅限.NET Framework):一个Windows窗体组件,定期触发事件。该组件没有用户界面,设计用于单线程环境
    • System.Web.UI.Timer(仅限.NET Framework):一个ASP.NET组件,以固定的间隔执行异步或同步网页回发

    这感觉像是一个X-Y问题。你到底想用这两个线程做什么?@AKX我想写一个简单的游戏,主线程是我的游戏循环,我想有第二个线程来跟踪VBlank发生的时间(使用
    D3DKMTWaitForVerticalBlankEvent()
    ,它会阻塞,所以我必须使用另一个线程)所以我可以计算出准确的刷新率。我的显示器显示它是60Hz,但实际上它大约是59.920Hz,在一个无争议的测试中大约需要20纳秒的CPU时间。这对你的心跳线程来说是不是太晚了?@TheodorZoulias请阅读我的最新问题,在我的用例中没有它我能逃脱吗?使用
    锁的优点/缺点是什么?(主线程中的循环将运行与FPS相同的次数,例如,如果游戏以120FPS的速度运行,它将每秒循环120次,每个循环将读取
    Interval
    一次。)我上面发布的代码是一个非常简化的版本(完整的代码非常混乱…)我不需要主线程在
    Interval
    更新后立即执行某些操作。我将编辑问题以添加更多信息。
    int interval;
    while (Interval < 100 /* I could use some other condition not invoving Interval */ ) {
        interval = Interval;
        // all usage of "Interval" from this point would use the value read in interval
        Console.WriteLine($"Interval  : {interval}");
        Thread.Sleep(100);
    }