Мне нужен надежный способ получить бесперебойную работу системы и в конечном итоге использовать что-то следующее. Добавлены комментарии, чтобы помочь людям прочитать его. Я не могу использовать Task, поскольку это должно выполняться в приложении .NET 3.5.Система Uptime & MemoryBarrier
// 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()
? Я размещаю его перед чтением значения, но либо текущий поток, либо другой поток мог бы записать на него. Правильно ли это выглядит?
Edit, ответ, основанный на Daniel
Это то, что я eneded до реализации, спасибо вам обоим за понимание.
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());
}
}
Edit 2
обновляется на основе комментариев Боба.
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()));
}
}
Вы говорите, что счетчик perf может стать коррумпированным в течение срока службы приложения? вот почему вы каждый раз запускаете новый поток для проверки? –
@Bobb, ммм не уверен. Мое приложение - это служба Windows, которая запускается при запуске машины. Я видел, что он поврежден, и мое приложение всегда работает. Вероятно, это произойдет в течение всего срока службы приложения на некоторых машинах. PS, я ценю, что я могу сделать некоторое кэширование, добавить DateTime.Now в качестве переменной-члена, и если они оба не нуль вычисляют новое значение времени безотказной работы. Вероятно, изменит код, чтобы сделать это, чтобы гарантировать, что я не создаю потенциальную нагрузку «неаборируемых» потоков. –
Создание и запуск потока, чтобы получить значение таймера, настолько ошибочно, что я даже не знаю, с чего начать. вы должны сделать снимок времени безотказной работы как-то в начале (я не могу прокомментировать ваше понятие «коррупция») и местное время, используя часы привет-res (много примеров в google). и на каждом GetUpTime вы просто возвращаете initialUpTime + (timeNow - timeAtUpTimeSnapshot). этот вызов займет несколько строк кода, будет синхронным, предсказуемым и управляемым ... то, что вы сейчас делаете, не имеет никакого смысла. –