Когда я устанавливаю класс приоритета процесса в реальном времени в .NET:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
Он отображается только как "Высокий" приоритет в диспетчере задач:
Если я вручную установлю его в реальном времени в диспетчере задач, а затем снова Process.GetCurrentProcess()
, ProcessPriorityClass
по-прежнему будет Process.GetCurrentProcess()
как ProcessPriorityClass.RealTime
.
Если я запускаю приложение от имени администратора, то класс приоритета меняется на Реальное время, как сообщает диспетчер задач. Таким образом, кажется, что при работе от имени обычного пользователя вы можете установить его в RealTime, и он будет сообщаться как таковой .NET, но фактический приоритет процесса на самом деле просто высокий. Почему .NET и TaskManager сообщают разные значения в этом случае?
Настоящий виновник здесь - Windows.
Установщик свойства PriorityClass
прост:
set {
if (!Enum.IsDefined(typeof(ProcessPriorityClass), value)) {
throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessPriorityClass));
}
// BelowNormal and AboveNormal are only available on Win2k and greater.
if (((value & (ProcessPriorityClass.BelowNormal | ProcessPriorityClass.AboveNormal)) != 0) &&
(OperatingSystem.Platform != PlatformID.Win32NT || OperatingSystem.Version.Major < 5)) {
throw new PlatformNotSupportedException(SR.GetString(SR.PriorityClassNotSupported), null);
}
SafeProcessHandle handle = null;
try {
handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
if (!NativeMethods.SetPriorityClass(handle, (int)value)) {
throw new Win32Exception();
}
priorityClass = value;
havePriorityClass = true;
}
finally {
ReleaseProcessHandle(handle);
}
}
После нескольких проверок SetPriorityClass
он вызывает Windows API SetPriorityClass
, а затем проверяет код возврата. Если возникает ошибка, выдается исключение. В противном случае он локально сохраняет значение нового приоритета (чтобы при чтении значения PriorityClass
ему не приходилось вызывать Windows обратно, чтобы проверить его).
В некоторых случаях Windows будет отказывать в изменении приоритета (например, как вы заметили, теперь вам нужны права администратора для установки приоритета в реальном времени). Хитрость в том, что Windows молча отрицает изменение приоритета и не возвращает код ошибки. Как задокументировано здесь:
Обратите внимание, что вызов SetPriorityClass() может вернуть успех, даже если приоритет не был установлен в REALTIME_PRIORITY_CLASS, потому что, если у вас нет разрешения Увеличение приоритета планирования, запрос REALTIME_PRIORITY_CLASS интерпретируется как запрос для класса наивысшего приоритета, разрешенного в текущий счет.
Я предполагаю, что это сделано, чтобы избежать взлома унаследованных приложений, которые не ожидают, что их вызов потерпит неудачу. Из-за этого ваше приложение .NET не знает, что изменение приоритета не сработало, как ожидалось, и возвращает неправильное значение.
Тем не менее, даже если Windows действительно установит приоритет, как и ожидалось, код .NET все равно не будет работать в некоторых случаях. Например, представьте, что вы установили для PriorityClass
значение BelowNormal
. Это значение будет храниться локально в объекте Process
, как описано выше. Затем, если вы снова измените приоритет, но из диспетчера задач, как и раньше,.NET не узнает об этом и вернет старое значение.
Если вам абсолютно необходима актуальная информация, сначала вызовите process.Refresh()
чтобы очистить локально сохраненное значение.
process.PriorityClass = ProcessPriorityClass.RealTime; Console.WriteLine($"Priority class cached: {process.PriorityClass}"); process.Refresh(); Console.WriteLine($"Actual priority class: {process.PriorityClass}");
При запуске без прав администратора печатает: Priority class assumed: RealTime Actual priority class: High
Так что все верно, проблема в том, что класс Process кэширует предполагаемое значение, а не получает его из Windows.