пятница, 23 декабря 2022 г.

[prog] Столкнулся с (не)ожиданным поведением WaitForMultipleObjects

Есть программулина, которая читает stdout/err нескольких дочерних процессов. Под Windows для этих целей используется WaitForMultipleObjects. Посредством этой функции определяется какой именно из N имеющихся хэндлов готов для чтения.

Обратил внимание на то, что когда дочерние процессы очень активно печатают в stdout, то программулина, в основном, читает выхлоп первого дочернего процесса, иногда читается и выхлоп второго, а вот до чтения выхлопов остальных процессов дело редко доходит.

Подумалось, что это происходит из-за того, что хэндлы передаются в WaitForMultipleObjects всегда в одном и том же порядке. Т.е. практически всегда формируется один и тот же вектор значений [h1, h2, h3, h4, ..., hN]. Поэтому, когда WaitForMultipleObjects начинает проверять готовность хэндлов, то сперва проверяется h1, затем h2, затем h3 и т.д.

Когда дочерние процессы пишут в stdout активно, то выясняется, что h1 практически всегда готов для чтения. А в тех редких случаях, когда мы успели вычитать все из h1, а новое туда еще не попало, готовым к чтению оказывается h2. Иногда дело доходит даже до h3. Но вот дальше практически никогда не продвигаемся.

Применил простой трюк: перед каждым вызовом WaitForMultipleObjects происходит сдвиг содержимого вектора хэндлов. Т.е. на первой итерации передается [h1, h2, h3, h4, ..., hN], на второй [h2, h3, h4, ..., hN, h1], на третьей [h3, h4, ..., hN, h1, h2], на четвертой [h4, ..., hN, h1, h2, h3] и т.д.

В результате равномерность чтения того, что пишут дочерние процессы, значительно улучшилась. По крайней мере на глазок.

Решил зафиксировать этот трюк в блоге. Т.к., во-первых, для меня лично такое поведение WaitForMultipleObjects оказалось неожиданным. Но, если вдуматься, то оно вполне себе логично.

Во-вторых, в теме работы с Win32 API я "не настоящий сварщик", чего-то наверняка не знаю. Поэтому если это читают люди с большим опытом, то буду признателен если мне подскажут как надо было бы поступить.

1 комментарий:

Stanislav Mischenko комментирует...

WaitForMultipleObjects возвращает индекс 1-ого готового объекта, даже если их больше чем один. Соответственно остальные надо проверить вручную. Ваше решение тоже вариант. Решайте сами, что лучше.