Ранние пробуждения в WaitForSingleObject () ...? - PullRequest
0 голосов
/ 08 июля 2019

Все, что я прочитал как на сайте MS docs (где он на самом деле не адресован), так и здесь, в SO, говорит о том, что Windows WaitForSingleObject() не подвержена ложным пробуждениям и ожидает как минимум предоставленное время, и, возможно,дольше.Тем не менее, мое тестирование говорит, что это не так, и на самом деле ранние пробуждения случаются почти всегда.Является ли «здравый смысл» неправильным, и мне просто нужно добавить циклы для обработки ранних пробуждений, или я делаю что-то не так, и мне нужно постоянно биться головой об этом, чтобы попытаться выяснить?

К сожалению, полныйкод слишком сложен для размещения здесь, но у меня есть две разные темы, каждая со своим собственным событием, созданным с помощью:

event = CreateEventA(NULL, false, false, NULL);

(событие является локальной переменной потока).У меня есть мьютекс, который я использую для обеспечения того, чтобы оба потока запускались примерно в одно и то же время.

В каждом потоке я вызываю WaitForSingleObject().В этом конкретном тесте я никогда не вызываю SetEvent(), поэтому единственный способ закончить это через тайм-аут, и код возврата показывает, что это происходит.Однако фактическое количество времени, затрачиваемое на ожидание, сильно варьируется, и 90% времени на меньше , чем запрошенное мной время.Я инструктировал это, используя QueryPerformanceCounter(), чтобы определить, сколько времени здесь проведено, и это просто неправильно.Вот инструментальный код:

LARGE_INTEGER freq, ctr1, ctr2;
QueryPerformanceFrequency(&freq);

QueryPerformanceCounter(&ctr1);
DWORD ret = WaitForSingleObject(event, tmoutMs);
QueryPerformanceCounter(&ctr2);

uint64_t elapsed = ((uint64_t)ctr2.QuadPart - (uint64_t)ctr1.QuadPart) * 1000000ULL / (uint64_t)freq.QuadPart;

(здесь elapsed хранится в микросекундах, просто чтобы быть более конкретным) Затем я распечатываю эту информацию.В одном потоке tmoutMs равен 2, а в другом потоке tmoutMs равен 100. Почти каждый раз, когда возвращаемые значения слишком короткие: ожидание 2 мс может занять от 700 мкс, а ожидание 100 мс - от 93 мс.Только один раз в 7 попыток или около того истекшее время будет> 100 мс.Вот некоторые примеры выходных данных:

event=104: pause(tmoutMs=2) => ret=258 elapsed us=169, ms=0
event=112: pause(tmoutMs=100) => ret=258 elapsed us=93085, ms=93

event=104: pause(tmoutMs=2) => ret=258 elapsed us=427, ms=0
event=112: pause(tmoutMs=100) => ret=258 elapsed us=94002, ms=94

event=104: pause(tmoutMs=2) => ret=258 elapsed us=3317, ms=3
event=112: pause(tmoutMs=100) => ret=258 elapsed us=96840, ms=96

event=104: pause(tmoutMs=2) => ret=258 elapsed us=11461, ms=11
event=112: pause(tmoutMs=100) => ret=258 elapsed us=105189, ms=105

Код возврата всегда WAIT_TIMEOUT, как и ожидалось.

Это разумно, даже если это не задокументировано (или задокументировано где-то, что я просто могу ')не могу найти), и мне просто нужно сделать цикл самостоятельно для обработки ранних пробуждений?

FWIW, это программа на C ++, скомпилированная с Visual Studio 2017, работающая на Windows10.Это программа модульного тестирования, использующая Google Test, и не имеет графического интерфейса: это только командная строка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...