Я запрашиваю значения регистров как часть модульного тестирования для пакетного скрипта, который настроит сеть для наших клиентов. Я определил состояние гонки, при котором запрос регистра после установки его значения в той же функции вызывает старое значение, пока вы не запустите командный файл повторно. Пример в моем блоке кода выглядит следующим образом:
:MyFunctionName
REM some initialization code
powercfg /change monitor-timeout-ac 2 1> nul
powercfg /change standby-timeout-ac 2 1> nul
powercfg /change hibernate-timeout-ac 2 1> nul
REM code that gets register paths setup and does some other irrelevant stuff
REM MonitorTimeoutPath is the path to the first powercfg setting
REM StandbyTimeoutPath is the path to the second setting
REM HibernateTimeoutPath is the path to the third setting
FOR /F "tokens=1-3 skip=2" %%A IN ('reg query "!MonitorTimeoutPath!" /v ACSettingIndex') DO (set /A "ActualMonitorTimeout=%%C/60")
FOR /F "tokens=1-3 skip=2" %%A IN ('reg query "!StandbyTimeoutPath!" /v ACSettingIndex') DO (set /A "ActualStandbyTimeout=%%C/60")
FOR /F "tokens=1-3 skip=2" %%A IN ('reg query "!HibernateTimeoutPath!" /v ACSettingIndex') DO (set /A "ActualHibernateTimeout=%%C/60")
REM code that tests values but is important for now
echo M:!ActualMonitorTimeout! S:!ActualStandbyTimeout! H:!ActualHibernateTimeout!
goto:EOF
Теперь вот важная вещь: когда я устанавливаю три параметра powercfg на разные значения (скажем, 1,1,2 соответственно), в ПЕРВЫЙ раз, когда я запускаю пакетный файл, оператор echo показывает мне значения 0,0,0. и только когда я запускаю файл ВТОРОЙ раз, я вижу истинные значения 1,1,2. Так как я на 99,99% уверен, что не обращаюсь к нему неправильно, потому что я использую ОЧЕНЬ похожие операторы FOR, чтобы получить данные регистра, когда я делаю это вне той же функции, как эта:
reg add "HKEY_CURRENT_USER\Control Panel\Accessibility\StickyKeys" /v Flags /t REG_SZ /d 10 /f 1> nul
call :RegTestFunc "HKEY_CURRENT_USER\Control Panel\Accessibility\StickyKeys" Flags 10
:RegTestFunc
REM some code
FOR /F "tokens=1-3 skip=2" %%A IN ('reg query "%~1" /v %~2 2^>nul') DO (set /A "RegisterData=%%C")
REM some more code
goto:EOF
Таким образом, нет практически никакой разницы, кроме некоторых математических различий (поэтому я не мог использовать функцию) и некоторого синтаксиса (потому что это функция). Дело в том, что мой синтаксис здесь, кажется, в порядке, и это не вызывает гоночных условий, когда я использую RegTestFunc
. Это происходит только тогда, когда я непосредственно запускаю операцию запроса в той же функции, для которой я установил значение регистра.
Чтобы попытаться решить эту проблему, я попытался выяснить, какая (если есть) форма пакета управления таймированием, и я наткнулся на команду timeout. Я использовал его, думая, что могу задержать процессор, так что значение регистра будет изменено к тому времени, когда оно было запрошено. В частности, я поставил его перед 3 FOR
операторами, которые запрашивают данные из регистра. Это не сработало, поэтому я и спрашиваю здесь, потому что Google - бесполезная поисковая система для чего-то интересного. Существует ли простой способ заблокировать операцию запроса или ее результаты, чтобы я всегда получал самые последние изменения? Я почти уверен, что cmd работает так быстро, что команда powercfg / change не может выполнить свою работу, пока не поступит команда reg query и не запросит устаревшие данные. В случае необходимости я мог бы просто сделать другую функцию и вызвать ее и посмотреть, не изменит ли это что-то, но это грязно, поэтому я бы хотел этого избежать.
Для справки: Каким будет технический термин для этой проблемы? Я не рассматриваю это как условие гонки, потому что нет нескольких потоков, борющихся за одни и те же данные регистра, это не проблема производителя, потому что данные есть, они просто не распознаются. Тем не менее, эти концепции очень похожи на то, что происходит на самом деле (по крайней мере, для меня), так как будет называться эта «проблема»? Данные изменяются / запрашиваются слишком быстро, но как это будет формально называться (если что)? Моей первой мыслью было состояние гонки, затем потребитель-производитель, затем устаревшие данные, и я решил, что проблема синхронизации будет лучшим словом, которое я буду использовать для описания того, что, по моему мнению, происходит.
UPDATE
Я пытался изменить все важные переменные с отложенным расширением (!) В моем коде на не задержанные (%), думая, что, возможно, он захватывал старые значения через расширение и область, но это не сработало, регистры все еще устарели одним запуском сценария. Я также попытался дважды запросить регистры и использовать вспомогательную функцию для разделения кода и посмотреть, сработало ли это, но все же не сработало. Мое единственное предположение, что изменения в powercfg не завершаются до тех пор, пока не будет достигнут последний оператор пакетного скрипта, поэтому мой вопрос: как мне запросить точные данные до этого?
ОБНОВЛЕНИЕ 2
Я попытался экспортировать данные реестра сразу после того, как я их установил.
REM RUNNING THE FILE THE FIRST TIME ASSUMING THE VALUES WERE ALL 0 BEFORE
powercfg /change monitor-timeout-ac 3 1> nul
powercfg /change standby-timeout-ac 3 1> nul
powercfg /change hibernate-timeout-ac 3 1> nul
REM some code
REM the below isn't runnable but the idea is that it contains the path to
REM powercfg /change monitor-timeout-ac
reg export %MonitorTimeoutPath% foo.reg
(в foo.reg)
[HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Энергетика \ User \ PowerSchemes \ f4e62c59-ee57-456a-94c4-3662e9d6ceb9 \ 7516b95f-f776-4464-8c53-06167f40cc99 \ 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e]
"ACSettingIndex" = DWORD: 00000000
Обратите внимание на шестнадцатеричное значение 00 в конце (0 секунд или 0 минут)
Тогда, если вы запустите указанный выше сценарий ДАЖЕ без строк:
REM RUNNING THE FILE THE SECOND TIME
powercfg /change monitor-timeout-ac 3 1> nul
powercfg /change standby-timeout-ac 3 1> nul
powercfg /change hibernate-timeout-ac 3 1> nul
Вы получите правильное значение
[HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Энергетика \ User \ PowerSchemes \ f4e62c59-ee57-456a-94c4-3662e9d6ceb9 \ 7516b95f-f776-4464-8c53-06167f40cc99 \ 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e]
"ACSettingIndex" = DWORD: 000000B4
(шестнадцатеричный 180 секунд или 3 минуты)
И только после двухкратного запуска пакетного файла фактическое значение обновляется ДАЖЕ ЕСЛИ Я закомментирую строки записи powercfg при втором запуске, так что запись в реестр происходит только один раз. Это означает, что сам реестр еще не получил данные, когда мы запрашиваем сразу после изменения настроек powercfg. Я исследовал проблему и мне нужна реализация
RegFlushKey(hkey key);
Который, по-видимому, существует в C и вызывает обновление реестра указанного ключа (он немедленно записывает этот реестр на «диск» и останавливает все остальное, поэтому работает медленно). Все это детализировано намного лучше здесь: https://docs.microsoft.com/en-gb/windows/desktop/api/winreg/nf-winreg-regflushkey и мне нужен способ сделать это в основном в пакетном режиме.