Решение 11 распространенных проблем в многопоточном коде - Двухшажный танец
ОГЛАВЛЕНИЕ
Двухшажный танец
Порой возникает необходимость оповестить о событии, удерживая блокировку. Это может быть некстати, если пробуждающемуся потоку необходимо получить удерживаемую блокировку, поскольку он будет пробужден только для того, чтобы ждать дальше. Это приводит к бесполезному расходу ресурсов и увеличивает число общих переключений контекста. Эта ситуация называется двухшажным танцем и может выходить далеко за пределы двух шагов в тех случаях, когда задействовано много блокировок и событий.
Поддержка переменной условия как в Win32, так и в CLR по природе своей страдает от проблемы двухшажного танца Ее часто невозможно или чрезвычайно сложно обойти.
Проблема двухшагового танца еще острее на однопроцессорном компьютере. Когда задействованы события, ядро применит повышение приоритета к пробуждающемуся потоку. Это почти наверняка вытеснит поток, устанавливающий событие, прежде чем у того будет возможность освободить блокировку. Вот крайний случай двухшажного танца: устанавливающий поток ThreadA переключает контекст, чтобы пробуждающийся поток ThreadB мог попытаться приобрести блокировку; это, само собой, невозможно, так что он переключит контекст обратно, чтобы поток ThreadA мог запуститься снова; со временем поток ThreadA освободит блокировку, что снова увеличит приоритетность потока ThreadB, который вытеснит поток ThreadA, чтобы иметь возможность выполняться. Как можно убедиться, здесь наблюдается масса бесполезных переключений контекста.