【发布时间】:2019-11-02 10:22:38
【问题描述】:
我正在尝试创建一个具有 2 个线程的应用程序。在主线程中我有一个变量(Int32),我只能从主线程中读取。
现在我有另一个线程在循环运行,只要程序正在运行,这个线程就会创建一个“心跳”,当达到某个点时,我想更新上面所说的变量。变量只从这个心跳线程写入,从不从任何其他线程写入。
为了保持精度(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();
}
}
}
它运行,但我想知道我的做法是否正确。如果不是,我应该如何改进它?
总结:
-
Interval仅由主线程读取。 -
Interval仅由Heartbeat线程修改。 - 我想避免对
Heartbeat线程的任何阻塞,最好不要阻塞主线程。
编辑:
我刚刚意识到我在Heartbeat() 中使用while 块读取Interval,所以我将它从while (Interval < 100) 更改为while (counter < 100)
编辑2:
上面的代码是一个非常简化的版本,真正的代码有点乱,我认为发布所有的 API 部分对这个问题没有帮助。
我不需要在 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);
}
- 只要在主线程中读取的值是合法值(在
Heartbeat线程中计算)而不是其他值,我就可以接受。例如,如果值在我为这个循环读取它的同时更新,那么获取旧值或新值是可以的,只要它不是某个无礼的值。 (如果它读取旧值,它会在下一个循环中读取新值,对吗?)
【问题讨论】:
-
这感觉像是 X-Y 问题。你到底想用这两个线程做什么?
-
@AKX 我正在尝试编写一个简单的游戏,主线程将是我的游戏循环,我希望有第二个线程来跟踪 VBlank 何时发生(@987654336 @,它阻塞所以我必须使用另一个线程)所以我可以计算出准确的刷新率。我的显示器说它是 60Hz,但实际上它大约是 59.920Hz,用 UFO TEST 测试过
-
无争议的
lock花费大约 20 纳秒的 CPU 时间。这对您的心跳线程来说是否有太多延迟? -
@TheodorZoulias 请阅读我更新的问题,对于我的用例,我可以不使用它吗?使用
lock有什么好处/缺点? (主线程中的循环运行次数与 FPS 一样多,例如,如果游戏以 120FPS 运行,它将每秒循环 120 次,每个循环将读取一次Interval。)
标签: c# multithreading