gpt4 book ai didi

c# - 系统正常运行时间和 MemoryBarrier

转载 作者:太空狗 更新时间:2023-10-30 01:23:30 26 4
gpt4 key购买 nike

我需要一种可靠的方法来获得系统正常运行时间,并最终使用了如下方法。添加了一些评论以帮助人们阅读它。我不能使用任务,因为它必须在 .NET 3.5 应用程序上运行。

// This is a structure, can't be marked as volatile
// need to implement MemoryBarrier manually as appropriate
private static TimeSpan _uptime;

private static TimeSpan GetUptime()
{
// Try and set the Uptime using per counters
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();

// If our thread hasn't finished in 5 seconds, perf counters are broken
if (!uptimeThread.Join(5 * 1000))
{
// Kill the thread and use Environment.TickCount
uptimeThread.Abort();
_uptime = TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}

Thread.MemoryBarrier();
return _uptime;
}

// This sets the System uptime using the perf counters
// this gives the best result but on a system with corrupt perf counters
// it can freeze
private static void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}

我纠结的部分是 Thread.MemoryBarrier() 应该放在哪里?我在读取值之前放置它,但当前线程或其他线程可能已写入它。以上看起来正确吗?

编辑,根据大牛回答

这就是我最终实现的,感谢你们的洞察力。

private static TimeSpan _uptime;

private static TimeSpan GetUptime()
{
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();

if (uptimeThread.Join(5*1000))
{
return _uptime;
}
else
{
uptimeThread.Abort();
return TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}
}

private static void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}

编辑2

根据 Bob 的评论更新。

private static DateTimeOffset _uptime;

private static DateTimeOffset GetUptime()
{
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();

if (uptimeThread.Join(5*1000))
{
return _uptime;
}
else
{
uptimeThread.Abort();
return DateTimeOffset.Now.Subtract(TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue));
}
}

private static void GetPerformanceCounterUptime()
{
if (_uptime != default(DateTimeOffset))
{
return;
}

using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = DateTimeOffset.Now.Subtract(
TimeSpan.FromSeconds(uptime.NextValue()));
}
}

最佳答案

Thread.Join 已经确保 uptimeThread 执行的写入在主线程上可见。您不需要任何明确的内存屏障。 (没有 Join 执行的同步,您需要在两个线程上设置屏障 - 在写入之后和读取之前)

但是,您的代码有一个潜在的问题:写入 TimeSpan 结构不是原子的,主线程和 uptimeThread 可能会同时写入它(Thread .Abort 只是表示中止,但不会等待线程完成中止),导致写入中断。我的解决方案是在中止时根本不使用该字段。此外,对 GetUptime() 的多个并发调用可能会导致相同的问题,因此您应该改用实例字段。

private static TimeSpan GetUptime()
{
// Try and set the Uptime using per counters
var helper = new Helper();
var uptimeThread = new Thread(helper.GetPerformanceCounterUptime);
uptimeThread.Start();

// If our thread hasn't finished in 5 seconds, perf counters are broken
if (uptimeThread.Join(5 * 1000))
{
return helper._uptime;
} else {
// Kill the thread and use Environment.TickCount
uptimeThread.Abort();
return TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}
}

class Helper
{
internal TimeSpan _uptime;

// This sets the System uptime using the perf counters
// this gives the best result but on a system with corrupt perf counters
// it can freeze
internal void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}
}

但是,我不确定中止性能计数器线程是否会正常工作 - Thread.Abort() 仅中止托管代码执行。如果代码在 Windows API 调用中挂起,线程将继续运行。

关于c# - 系统正常运行时间和 MemoryBarrier,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11102123/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com